QortalOS Brooklyn for Raspberry Pi 4
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

562 lines
22 KiB

/*
SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <[email protected]>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <QQmlParserStatus>
#include <QSortFilterProxyModel>
#include <QScopedPointer>
#include "notificationmanager_export.h"
namespace NotificationManager
{
/**
* @brief A model with notifications and jobs
*
* This model contains application notifications as well as jobs
* and lets you apply fine-grained filter, sorting, and grouping rules.
*
* @author Kai Uwe Broulik <[email protected]>
**/
class NOTIFICATIONMANAGER_EXPORT Notifications : public QSortFilterProxyModel, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
/**
* The number of notifications the model should at most contain.
*
* Default is 0, which is no limit.
*/
Q_PROPERTY(int limit READ limit WRITE setLimit NOTIFY limitChanged)
/**
* Whether to show expired notifications.
*
* Expired notifications are those that timed out, i.e. ones that were not explicitly
* closed or acted upon by the user, nor revoked by the issuing application.
*
* An expired notification has its actions removed.
*
* Default is false.
*/
Q_PROPERTY(bool showExpired READ showExpired WRITE setShowExpired NOTIFY showExpiredChanged)
/**
* Whether to show dismissed notifications.
*
* Dismissed notifications are those that are temporarily hidden by the user.
* This can e.g. be a copy job that has its popup closed but still continues in the background.
*
* Default is false.
*/
Q_PROPERTY(bool showDismissed READ showDismissed WRITE setShowDismissed NOTIFY showDismissedChanged)
/**
* A list of desktop entries for which no notifications should be shown.
*
* If the same desktop entry is present in both blacklist and whitelist,
* the blacklist takes precedence, i.e. the notification is not shown.
*/
Q_PROPERTY(QStringList blacklistedDesktopEntries READ blacklistedDesktopEntries WRITE setBlacklistedDesktopEntries NOTIFY blacklistedDesktopEntriesChanged)
/**
* A list of notifyrc names for which no notifications should be shown.
*
* If the same notifyrc name is present in both blacklist and whitelist,
* the blacklist takes precedence, i.e. the notification is not shown.
*/
Q_PROPERTY(QStringList blacklistedNotifyRcNames READ blacklistedNotifyRcNames WRITE setBlacklistedNotifyRcNames NOTIFY blacklistedNotifyRcNamesChanged)
/**
* A list of desktop entries for which notifications should be shown.
*
* This bypasses any filtering for urgency.
*
* If the same desktop entry is present in both whitelist and blacklist,
* the blacklist takes precedence, i.e. the notification is not shown.
*
* Default is empty list, which means normal filtering is applied.
*/
Q_PROPERTY(QStringList whitelistedDesktopEntries READ whitelistedDesktopEntries WRITE setWhitelistedDesktopEntries NOTIFY whitelistedDesktopEntriesChanged)
/**
* A list of notifyrc names for which notifications should be shown.
*
* This bypasses any filtering for urgency.
*
* If the same notifyrc name is present in both whitelist and blacklist,
* the blacklist takes precedence, i.e. the notification is not shown.
*
* Default is empty list, which means normal filtering is applied.
*/
Q_PROPERTY(QStringList whitelistedNotifyRcNames READ whitelistedNotifyRcNames WRITE setWhitelistedNotifyRcNames NOTIFY whitelistedNotifyRcNamesChanged)
/**
* Whether to show notifications.
*
* Default is true.
*/
Q_PROPERTY(bool showNotifications READ showNotifications WRITE setShowNotifications NOTIFY showNotificationsChanged)
/**
* Whether to show application jobs.
*
* Default is false.
*/
Q_PROPERTY(bool showJobs READ showJobs WRITE setShowJobs NOTIFY showJobsChanged)
/**
* The notification urgency types the model should contain.
*
* Default is all urgencies: low, normal, critical.
*/
Q_PROPERTY(Urgencies urgencies READ urgencies WRITE setUrgencies NOTIFY urgenciesChanged)
/**
* The sort mode for notifications.
*
* Default is strictly by date created/updated.
*/
Q_PROPERTY(SortMode sortMode READ sortMode WRITE setSortMode NOTIFY sortModeChanged)
/**
* The sort order for notifications.
*
* This only affects the sort order by date. When @c sortMode is set to SortByTypeAndUrgency
* the order of notification groups (e.g. high - jobs - normal - low) is unaffected, and only
* notifications within the same group are either sorted ascending or descending by their
* creation/update date.
*
* Default is DescendingOrder, i.e. newest notifications come first.
*
* @since 5.19
*/
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
/**
* The group mode for notifications.
*
* Default is ungrouped.
*/
Q_PROPERTY(GroupMode groupMode READ groupMode WRITE setGroupMode NOTIFY groupModeChanged)
/**
* How many notifications are shown in each group.
*
* You can expand a group by setting the IsGroupExpandedRole to true.
*
* Default is 0, which means no limit.
*/
Q_PROPERTY(int groupLimit READ groupLimit WRITE setGroupLimit NOTIFY groupLimitChanged)
/**
* Whether to automatically show notifications that are unread.
*
* This is any notification that was created or updated after the value of @c lastRead.
*/
Q_PROPERTY(bool expandUnread READ expandUnread WRITE setExpandUnread NOTIFY expandUnreadChanged)
/**
* The number of notifications in the model
*/
Q_PROPERTY(int count READ count NOTIFY countChanged)
/**
* The number of active, i.e. non-expired notifications
*/
Q_PROPERTY(int activeNotificationsCount READ activeNotificationsCount NOTIFY activeNotificationsCountChanged)
/**
* The number of inactive, i.e. non-expired notifications
*/
Q_PROPERTY(int expiredNotificationsCount READ expiredNotificationsCount NOTIFY expiredNotificationsCountChanged)
/**
* The time when the user last could read the notifications.
* This is typically reset whenever the list of notifications is opened and is used to determine
* the @c unreadNotificationsCount
*/
Q_PROPERTY(QDateTime lastRead READ lastRead WRITE setLastRead RESET resetLastRead NOTIFY lastReadChanged)
/**
* The number of notifications added since lastRead
*
* This can be used to show a "n unread notifications" label
*/
Q_PROPERTY(int unreadNotificationsCount READ unreadNotificationsCount NOTIFY unreadNotificationsCountChanged)
/**
* The number of active jobs
*/
Q_PROPERTY(int activeJobsCount READ activeJobsCount NOTIFY activeJobsCountChanged)
/**
* The combined percentage of all jobs.
*
* This is the average of all percentages and could can be used to show
* a global progress bar.
*/
Q_PROPERTY(int jobsPercentage READ jobsPercentage NOTIFY jobsPercentageChanged)
public:
explicit Notifications(QObject *parent = nullptr);
~Notifications() override;
enum Roles {
IdRole = Qt::UserRole + 1, ///< A notification identifier. This can be uint notification ID or string application job source.
SummaryRole = Qt::DisplayRole, ///< The notification summary.
ImageRole = Qt::DecorationRole, ///< The notification main image, which is not the application icon. Only valid for pixmap icons.
IsGroupRole = Qt::UserRole + 2, ///< Whether the item is a group
GroupChildrenCountRole, ///< The number of children in a group.
ExpandedGroupChildrenCountRole, ///< The number of children in a group that are expanded.
IsGroupExpandedRole, ///< Whether the group is expanded, this role is writable.
IsInGroupRole, ///< Whether the notification is currently inside a group.
TypeRole, ///< The type of model entry, either NotificationType or JobType.
CreatedRole, ///< When the notification was first created.
UpdatedRole, ///< When the notification was last updated, invalid when it hasn't been updated.
BodyRole, ///< The notification body text.
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
///< exposed as ImageRole instead.
DesktopEntryRole, ///< The desktop entry (without .desktop suffix, e.g. org.kde.spectacle) of the application that sent the notification.
NotifyRcNameRole, ///< The notifyrc name (e.g. spectaclerc) of the application that sent the notification.
ApplicationNameRole, ///< The user-visible name of the application (e.g. Spectacle)
ApplicationIconNameRole, ///< The icon name of the application
OriginNameRole, ///< The name of the device or account the notification originally came from, e.g. "My Phone" (in case of device sync) or
///< "[email protected]" (in case of an email notification)
// Jobs
JobStateRole, ///< The state of the job, either JobStateJopped, JobStateSuspended, or JobStateRunning.
PercentageRole, ///< The percentage of the job. Use @c jobsPercentage to get a global percentage for all jobs.
JobErrorRole, ///< The error id of the job, zero in case of no error.
SuspendableRole, ///< Whether the job can be suspended @sa suspendJob
KillableRole, ///< Whether the job can be killed/canceled @sa killJob
JobDetailsRole, ///< A pointer to a Job item itself containing more detailed information about the job
ActionNamesRole, ///< The IDs of the actions, excluding the default and settings action, e.g. [action1, action2]
ActionLabelsRole, ///< The user-visible labels of the actions, excluding the default and settings action, e.g. ["Accept", "Reject"]
HasDefaultActionRole, ///< Whether the notification has a default action, which is one that is invoked when the popup itself is clicked
DefaultActionLabelRole, ///< The user-visible label of the default action, typically not shown as the popup itself becomes clickable
UrlsRole, ///< A list of URLs associated with the notification, e.g. a path to a screenshot that was just taken or image received
UrgencyRole, ///< The notification urgency, either LowUrgency, NormalUrgency, or CriticalUrgency. Jobs do not have an urgency.
TimeoutRole, ///< The timeout for the notification in milliseconds. 0 means the notification should not timeout, -1 means a sensible default should be
///< applied.
ConfigurableRole, ///< Whether the notification can be configured because a desktopEntry or notifyRcName is known, or the notification has a setting
///< action. @sa configure
ConfigureActionLabelRole, ///< The user-visible label for the settings action
ClosableRole, ///< Whether the item can be closed. Notifications are always closable, jobs are only when in JobStateStopped.
ExpiredRole, ///< The notification timed out and closed. Actions on it cannot be invoked anymore.
DismissedRole, ///< The notification got temporarily hidden by the user but could still be interacted with.
ReadRole, ///< Whether the notification got read by the user. If true, the notification isn't considered unread even if created after lastRead.
///< @since 5.17
UserActionFeedbackRole, ///< Whether this notification is a response/confirmation to an explicit user action. @since 5.18
HasReplyActionRole, ///< Whether the notification has a reply action. @since 5.18
ReplyActionLabelRole, ///< The user-visible label for the reply action. @since 5.18
ReplyPlaceholderTextRole, ///< A custom placeholder text for the reply action, e.g. "Reply to Max...". @since 5.18
ReplySubmitButtonTextRole, ///< A custom text for the reply submit button, e.g. "Submit Comment". @since 5.18
ReplySubmitButtonIconNameRole, ///< A custom icon name for the reply submit button. @since 5.18
CategoryRole, ///< The (optional) category of the notification. Notifications can optionally have a type indicator. Although neither client or nor
///< server must support this, some may choose to. Those servers implementing categories may use them to intelligently display the
///< notification in a certain way, or group notifications of similar types. @since 5.21
ResidentRole, ///< Whether the notification should keep its actions even when they were invoked. @since 5.22
TransientRole, ///< Whether the notification is transient and should not be kept in history. @since 5.22
};
Q_ENUM(Roles)
/**
* The type of model item.
*/
enum Type {
NoType,
NotificationType, ///< This item represents a notification.
JobType, ///< This item represents an application job.
};
Q_ENUM(Type)
/**
* The notification urgency.
*
* @note jobs do not have an urgency, yet still might be above normal urgency notifications.
*/
enum Urgency {
// these don't match the spec's value
LowUrgency = 1 << 0, ///< The notification has low urgency, it is not important and may not be shown or added to a history.
NormalUrgency = 1 << 1, ///< The notification has normal urgency. This is also the default if no urgecny is supplied.
CriticalUrgency = 1 << 2,
};
Q_ENUM(Urgency)
Q_DECLARE_FLAGS(Urgencies, Urgency)
Q_FLAG(Urgencies)
/**
* Which items should be cleared in a call to @c clear
*/
enum ClearFlag {
ClearExpired = 1 << 1,
// TODO more
};
Q_ENUM(ClearFlag)
Q_DECLARE_FLAGS(ClearFlags, ClearFlag)
Q_FLAG(ClearFlags)
/**
* The state an application job is in.
*/
enum JobState {
JobStateStopped, ///< The job is stopped. It has either finished (error is 0) or failed (error is not 0)
JobStateRunning, ///< The job is currently running.
JobStateSuspended, ///< The job is currentl paused
};
Q_ENUM(JobState)
/**
* The sort mode for the model.
*/
enum SortMode {
SortByDate = 0, ///< Sort notifications strictly by the date they were updated or created.
// should this be flags? SortJobsFirst | SortByUrgency | ...?
SortByTypeAndUrgency, ///< Sort notifications taking into account their type and urgency. The order is (descending): Critical, jobs, Normal, Low.
};
Q_ENUM(SortMode)
/**
* The group mode for the model.
*/
enum GroupMode {
GroupDisabled = 0,
// GroupApplicationsTree, // TODO make actual tree
GroupApplicationsFlat,
};
Q_ENUM(GroupMode)
enum InvokeBehavior {
None = 0,
Close = 1,
};
Q_ENUM(InvokeBehavior)
Q_DECLARE_FLAGS(InvokeBehaviors, InvokeBehavior)
Q_FLAG(InvokeBehaviors)
int limit() const;
void setLimit(int limit);
bool showExpired() const;
void setShowExpired(bool show);
bool showDismissed() const;
void setShowDismissed(bool show);
QStringList blacklistedDesktopEntries() const;
void setBlacklistedDesktopEntries(const QStringList &blacklist);
QStringList blacklistedNotifyRcNames() const;
void setBlacklistedNotifyRcNames(const QStringList &blacklist);
QStringList whitelistedDesktopEntries() const;
void setWhitelistedDesktopEntries(const QStringList &whitelist);
QStringList whitelistedNotifyRcNames() const;
void setWhitelistedNotifyRcNames(const QStringList &whitelist);
bool showNotifications() const;
void setShowNotifications(bool showNotifications);
bool showJobs() const;
void setShowJobs(bool showJobs);
Urgencies urgencies() const;
void setUrgencies(Urgencies urgencies);
SortMode sortMode() const;
void setSortMode(SortMode sortMode);
Qt::SortOrder sortOrder() const;
void setSortOrder(Qt::SortOrder sortOrder);
GroupMode groupMode() const;
void setGroupMode(GroupMode groupMode);
int groupLimit() const;
void setGroupLimit(int limit);
bool expandUnread() const;
void setExpandUnread(bool expand);
int count() const;
int activeNotificationsCount() const;
int expiredNotificationsCount() const;
QDateTime lastRead() const;
void setLastRead(const QDateTime &lastRead);
void resetLastRead();
int unreadNotificationsCount() const;
int activeJobsCount() const;
int jobsPercentage() const;
/**
* Convert the given QModelIndex into a QPersistentModelIndex
*/
Q_INVOKABLE QPersistentModelIndex makePersistentModelIndex(const QModelIndex &idx) const;
/**
* @brief Expire a notification
*
* Closes the notification in response to its timeout running out.
*
* Call this if you have an implementation that handles the timeout itself
* by having called @c stopTimeout
*
* @sa stopTimeout
*/
Q_INVOKABLE void expire(const QModelIndex &idx);
/**
* @brief Close a notification
*
* Closes the notification in response to the user explicitly closing it.
*
* When the model index belongs to a group, the entire group is closed.
*/
Q_INVOKABLE void close(const QModelIndex &idx);
/**
* @brief Configure a notification
*
* This will invoke the settings action, if available, otherwise open the
* kcm_notifications KCM for configuring the respective application and event.
*/
Q_INVOKABLE void configure(const QModelIndex &idx); // TODO pass ctx for transient handling
/**
* @brief Invoke the default notification action
*
* Invokes the action that should be triggered when clicking
* the notification bubble itself.
*/
Q_INVOKABLE void invokeDefaultAction(const QModelIndex &idx, InvokeBehavior behavior = None);
/**
* @brief Invoke a notification action
*
* Invokes the action with the given actionId on the notification.
* For invoking the default action, i.e. the one that is triggered
* when clicking the notification bubble, use invokeDefaultAction
*/
Q_INVOKABLE void invokeAction(const QModelIndex &idx, const QString &actionId, InvokeBehavior = None);
/**
* @brief Reply to a notification
*
* Replies to the given notification with the given text.
* @since 5.18
*/
Q_INVOKABLE void reply(const QModelIndex &idx, const QString &text, InvokeBehavior behavior);
/**
* @brief Start automatic timeout of notifications
*
* Call this if you no longer handle the timeout yourself.
*
* @sa stopTimeout
*/
Q_INVOKABLE void startTimeout(const QModelIndex &idx);
Q_INVOKABLE void startTimeout(uint notificationId);
/**
* @brief Stop the automatic timeout of notifications
*
* Call this if you have an implementation that handles the timeout itself
* taking into account e.g. whether the user is currently interacting with
* the notification to not close it under their mouse. Call @c expire
* once your custom timer has run out.
*
* @sa expire
*/
Q_INVOKABLE void stopTimeout(const QModelIndex &idx);
/**
* @brief Suspend a job
*/
Q_INVOKABLE void suspendJob(const QModelIndex &idx);
/**
* @brief Resume a job
*/
Q_INVOKABLE void resumeJob(const QModelIndex &idx);
/**
* @brief Kill a job
*/
Q_INVOKABLE void killJob(const QModelIndex &idx);
/**
* @brief Clear notifications
*
* Removes the notifications matching th ClearFlags from the model.
* This can be used for e.g. a "Clear History" action.
*/
Q_INVOKABLE void clear(ClearFlags flags);
/**
* Returns a model index pointing to the group of a notification.
*/
Q_INVOKABLE QModelIndex groupIndex(const QModelIndex &idx) const;
Q_INVOKABLE void collapseAllGroups();
QVariant data(const QModelIndex &index, int role) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
Q_SIGNALS:
void limitChanged();
void showExpiredChanged();
void showDismissedChanged();
void blacklistedDesktopEntriesChanged();
void blacklistedNotifyRcNamesChanged();
void whitelistedDesktopEntriesChanged();
void whitelistedNotifyRcNamesChanged();
void showNotificationsChanged();
void showJobsChanged();
void urgenciesChanged();
void sortModeChanged();
void sortOrderChanged();
void groupModeChanged();
void groupLimitChanged();
void expandUnreadChanged();
void countChanged();
void activeNotificationsCountChanged();
void expiredNotificationsCountChanged();
void lastReadChanged();
void unreadNotificationsCountChanged();
void activeJobsCountChanged();
void jobsPercentageChanged();
protected:
void classBegin() override;
void componentComplete() override;
private:
class Private;
QScopedPointer<Private> d;
};
} // namespace NotificationManager
Q_DECLARE_OPERATORS_FOR_FLAGS(NotificationManager::Notifications::Urgencies)