mirror of https://github.com/Qortal/Brooklyn
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.
834 lines
23 KiB
834 lines
23 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 |
|
*/ |
|
|
|
#include "notifications.h" |
|
|
|
#include <QDebug> |
|
#include <QMetaEnum> |
|
#include <QSharedPointer> |
|
|
|
#include <KConcatenateRowsProxyModel> |
|
#include <KDescendantsProxyModel> |
|
|
|
#include "limitedrowcountproxymodel_p.h" |
|
#include "notificationfilterproxymodel_p.h" |
|
#include "notificationgroupcollapsingproxymodel_p.h" |
|
#include "notificationgroupingproxymodel_p.h" |
|
#include "notificationsmodel.h" |
|
#include "notificationsortproxymodel_p.h" |
|
|
|
#include "jobsmodel.h" |
|
|
|
#include "settings.h" |
|
|
|
#include "notification.h" |
|
|
|
#include "utils_p.h" |
|
|
|
#include "debug.h" |
|
|
|
using namespace NotificationManager; |
|
|
|
class Q_DECL_HIDDEN Notifications::Private |
|
{ |
|
public: |
|
explicit Private(Notifications *q); |
|
~Private(); |
|
|
|
void initSourceModels(); |
|
void initProxyModels(); |
|
|
|
void updateCount(); |
|
|
|
bool showNotifications = true; |
|
bool showJobs = false; |
|
|
|
Notifications::GroupMode groupMode = Notifications::GroupDisabled; |
|
int groupLimit = 0; |
|
bool expandUnread = false; |
|
|
|
int activeNotificationsCount = 0; |
|
int expiredNotificationsCount = 0; |
|
|
|
int unreadNotificationsCount = 0; |
|
|
|
int activeJobsCount = 0; |
|
int jobsPercentage = 0; |
|
|
|
static bool isGroup(const QModelIndex &idx); |
|
static uint notificationId(const QModelIndex &idx); |
|
QModelIndex mapFromModel(const QModelIndex &idx) const; |
|
|
|
// NOTE when you add or re-arrange models make sure to update mapFromModel()! |
|
NotificationsModel::Ptr notificationsModel; |
|
JobsModel::Ptr jobsModel; |
|
QSharedPointer<Settings> settings() const; |
|
|
|
KConcatenateRowsProxyModel *notificationsAndJobsModel = nullptr; |
|
|
|
NotificationFilterProxyModel *filterModel = nullptr; |
|
NotificationSortProxyModel *sortModel = nullptr; |
|
NotificationGroupingProxyModel *groupingModel = nullptr; |
|
NotificationGroupCollapsingProxyModel *groupCollapsingModel = nullptr; |
|
KDescendantsProxyModel *flattenModel = nullptr; |
|
|
|
LimitedRowCountProxyModel *limiterModel = nullptr; |
|
|
|
private: |
|
Notifications *q; |
|
}; |
|
|
|
Notifications::Private::Private(Notifications *q) |
|
: q(q) |
|
{ |
|
} |
|
|
|
Notifications::Private::~Private() |
|
{ |
|
} |
|
|
|
void Notifications::Private::initSourceModels() |
|
{ |
|
Q_ASSERT(notificationsAndJobsModel); // initProxyModels must be called before initSourceModels |
|
|
|
if (showNotifications && !notificationsModel) { |
|
notificationsModel = NotificationsModel::createNotificationsModel(); |
|
connect(notificationsModel.data(), &NotificationsModel::lastReadChanged, q, [this] { |
|
updateCount(); |
|
Q_EMIT q->lastReadChanged(); |
|
}); |
|
notificationsAndJobsModel->addSourceModel(notificationsModel.data()); |
|
} else if (!showNotifications && notificationsModel) { |
|
notificationsAndJobsModel->removeSourceModel(notificationsModel.data()); |
|
disconnect(notificationsModel.data(), nullptr, q, nullptr); // disconnect all |
|
notificationsModel = nullptr; |
|
} |
|
|
|
if (showJobs && !jobsModel) { |
|
jobsModel = JobsModel::createJobsModel(); |
|
notificationsAndJobsModel->addSourceModel(jobsModel.data()); |
|
jobsModel->init(); |
|
} else if (!showJobs && jobsModel) { |
|
notificationsAndJobsModel->removeSourceModel(jobsModel.data()); |
|
jobsModel = nullptr; |
|
} |
|
} |
|
|
|
void Notifications::Private::initProxyModels() |
|
{ |
|
/* The data flow is as follows: |
|
* NOTE when you add or re-arrange models make sure to update mapFromModel()! |
|
* |
|
* NotificationsModel JobsModel |
|
* \\ / |
|
* \\ / |
|
* KConcatenateRowsProxyModel |
|
* ||| |
|
* ||| |
|
* NotificationFilterProxyModel |
|
* (filters by urgency, whitelist, etc) |
|
* | |
|
* | |
|
* NotificationSortProxyModel |
|
* (sorts by urgency, date, etc) |
|
* | |
|
* --- BEGIN: Only when grouping is enabled --- |
|
* | |
|
* NotificationGroupingProxyModel |
|
* (turns list into tree grouped by app) |
|
* //\\ |
|
* //\\ |
|
* NotificationGroupCollapsingProxyModel |
|
* (limits number of tree leaves for expand/collapse feature) |
|
* /\ |
|
* /\ |
|
* KDescendantsProxyModel |
|
* (flattens tree back into a list for consumption in ListView) |
|
* | |
|
* --- END: Only when grouping is enabled --- |
|
* | |
|
* LimitedRowCountProxyModel |
|
* (limits the total number of items in the model) |
|
* | |
|
* | |
|
* \o/ <- Happy user seeing their notifications |
|
*/ |
|
|
|
if (!notificationsAndJobsModel) { |
|
notificationsAndJobsModel = new KConcatenateRowsProxyModel(q); |
|
} |
|
|
|
if (!filterModel) { |
|
filterModel = new NotificationFilterProxyModel(); |
|
connect(filterModel, &NotificationFilterProxyModel::urgenciesChanged, q, &Notifications::urgenciesChanged); |
|
connect(filterModel, &NotificationFilterProxyModel::showExpiredChanged, q, &Notifications::showExpiredChanged); |
|
connect(filterModel, &NotificationFilterProxyModel::showDismissedChanged, q, &Notifications::showDismissedChanged); |
|
connect(filterModel, &NotificationFilterProxyModel::blacklistedDesktopEntriesChanged, q, &Notifications::blacklistedDesktopEntriesChanged); |
|
connect(filterModel, &NotificationFilterProxyModel::blacklistedNotifyRcNamesChanged, q, &Notifications::blacklistedNotifyRcNamesChanged); |
|
|
|
connect(filterModel, &QAbstractItemModel::rowsInserted, q, [this] { |
|
updateCount(); |
|
}); |
|
connect(filterModel, &QAbstractItemModel::rowsRemoved, q, [this] { |
|
updateCount(); |
|
}); |
|
connect(filterModel, |
|
&QAbstractItemModel::dataChanged, |
|
q, |
|
[this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) { |
|
Q_UNUSED(topLeft); |
|
Q_UNUSED(bottomRight); |
|
if (roles.isEmpty() || roles.contains(Notifications::UpdatedRole) || roles.contains(Notifications::ExpiredRole) |
|
|| roles.contains(Notifications::JobStateRole) || roles.contains(Notifications::PercentageRole) |
|
|| roles.contains(Notifications::ReadRole)) { |
|
updateCount(); |
|
} |
|
}); |
|
|
|
filterModel->setSourceModel(notificationsAndJobsModel); |
|
} |
|
|
|
if (!sortModel) { |
|
sortModel = new NotificationSortProxyModel(q); |
|
connect(sortModel, &NotificationSortProxyModel::sortModeChanged, q, &Notifications::sortModeChanged); |
|
connect(sortModel, &NotificationSortProxyModel::sortOrderChanged, q, &Notifications::sortOrderChanged); |
|
} |
|
|
|
if (!limiterModel) { |
|
limiterModel = new LimitedRowCountProxyModel(q); |
|
connect(limiterModel, &LimitedRowCountProxyModel::limitChanged, q, &Notifications::limitChanged); |
|
} |
|
|
|
if (groupMode == GroupApplicationsFlat) { |
|
if (!groupingModel) { |
|
groupingModel = new NotificationGroupingProxyModel(q); |
|
groupingModel->setSourceModel(filterModel); |
|
} |
|
|
|
if (!groupCollapsingModel) { |
|
groupCollapsingModel = new NotificationGroupCollapsingProxyModel(q); |
|
groupCollapsingModel->setLimit(groupLimit); |
|
groupCollapsingModel->setExpandUnread(expandUnread); |
|
groupCollapsingModel->setLastRead(q->lastRead()); |
|
groupCollapsingModel->setSourceModel(groupingModel); |
|
} |
|
|
|
sortModel->setSourceModel(groupCollapsingModel); |
|
|
|
flattenModel = new KDescendantsProxyModel(q); |
|
flattenModel->setSourceModel(sortModel); |
|
|
|
limiterModel->setSourceModel(flattenModel); |
|
} else { |
|
sortModel->setSourceModel(filterModel); |
|
limiterModel->setSourceModel(sortModel); |
|
delete flattenModel; |
|
flattenModel = nullptr; |
|
delete groupingModel; |
|
groupingModel = nullptr; |
|
} |
|
|
|
q->setSourceModel(limiterModel); |
|
} |
|
|
|
void Notifications::Private::updateCount() |
|
{ |
|
int active = 0; |
|
int expired = 0; |
|
int unread = 0; |
|
|
|
int jobs = 0; |
|
int totalPercentage = 0; |
|
|
|
// We want to get the numbers after main filtering (urgencies, whitelists, etc) |
|
// but before any limiting or group limiting, hence asking the filterModel for advice |
|
// at which point notifications and jobs also have already been merged |
|
for (int i = 0; i < filterModel->rowCount(); ++i) { |
|
const QModelIndex idx = filterModel->index(i, 0); |
|
|
|
if (idx.data(Notifications::ExpiredRole).toBool()) { |
|
++expired; |
|
} else { |
|
++active; |
|
} |
|
|
|
const bool read = idx.data(Notifications::ReadRole).toBool(); |
|
if (!active && !read) { |
|
QDateTime date = idx.data(Notifications::UpdatedRole).toDateTime(); |
|
if (!date.isValid()) { |
|
date = idx.data(Notifications::CreatedRole).toDateTime(); |
|
} |
|
|
|
if (notificationsModel && date > notificationsModel->lastRead()) { |
|
++unread; |
|
} |
|
} |
|
|
|
if (idx.data(Notifications::TypeRole).toInt() == Notifications::JobType) { |
|
if (idx.data(Notifications::JobStateRole).toInt() != Notifications::JobStateStopped) { |
|
++jobs; |
|
|
|
totalPercentage += idx.data(Notifications::PercentageRole).toInt(); |
|
} |
|
} |
|
} |
|
|
|
if (activeNotificationsCount != active) { |
|
activeNotificationsCount = active; |
|
Q_EMIT q->activeNotificationsCountChanged(); |
|
} |
|
if (expiredNotificationsCount != expired) { |
|
expiredNotificationsCount = expired; |
|
Q_EMIT q->expiredNotificationsCountChanged(); |
|
} |
|
if (unreadNotificationsCount != unread) { |
|
unreadNotificationsCount = unread; |
|
Q_EMIT q->unreadNotificationsCountChanged(); |
|
} |
|
if (activeJobsCount != jobs) { |
|
activeJobsCount = jobs; |
|
Q_EMIT q->activeJobsCountChanged(); |
|
} |
|
|
|
const int percentage = (jobs > 0 ? totalPercentage / jobs : 0); |
|
if (jobsPercentage != percentage) { |
|
jobsPercentage = percentage; |
|
Q_EMIT q->jobsPercentageChanged(); |
|
} |
|
|
|
// TODO don't Q_EMIT in dataChanged |
|
Q_EMIT q->countChanged(); |
|
} |
|
|
|
bool Notifications::Private::isGroup(const QModelIndex &idx) |
|
{ |
|
return idx.data(Notifications::IsGroupRole).toBool(); |
|
} |
|
|
|
uint Notifications::Private::notificationId(const QModelIndex &idx) |
|
{ |
|
return idx.data(Notifications::IdRole).toUInt(); |
|
} |
|
|
|
QModelIndex Notifications::Private::mapFromModel(const QModelIndex &idx) const |
|
{ |
|
QModelIndex resolvedIdx = idx; |
|
|
|
QAbstractItemModel *models[] = { |
|
notificationsAndJobsModel, |
|
filterModel, |
|
sortModel, |
|
groupingModel, |
|
groupCollapsingModel, |
|
flattenModel, |
|
limiterModel, |
|
}; |
|
|
|
// TODO can we do this with a generic loop like mapFromModel |
|
while (resolvedIdx.isValid() && resolvedIdx.model() != q) { |
|
const auto *idxModel = resolvedIdx.model(); |
|
|
|
// HACK try to find the model that uses the index' model as source |
|
bool found = false; |
|
for (QAbstractItemModel *model : models) { |
|
if (!model) { |
|
continue; |
|
} |
|
|
|
if (auto *proxyModel = qobject_cast<QAbstractProxyModel *>(model)) { |
|
if (proxyModel->sourceModel() == idxModel) { |
|
resolvedIdx = proxyModel->mapFromSource(resolvedIdx); |
|
found = true; |
|
break; |
|
} |
|
} else if (auto *concatenateModel = qobject_cast<KConcatenateRowsProxyModel *>(model)) { |
|
// There's no "sourceModels()" on KConcatenateRowsProxyModel |
|
if (idxModel == notificationsModel.data() || idxModel == jobsModel.data()) { |
|
resolvedIdx = concatenateModel->mapFromSource(resolvedIdx); |
|
found = true; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (!found) { |
|
break; |
|
} |
|
} |
|
return resolvedIdx; |
|
} |
|
|
|
QSharedPointer<Settings> Notifications::Private::settings() const |
|
{ |
|
static QWeakPointer<Settings> s_instance; |
|
if (!s_instance) { |
|
QSharedPointer<Settings> ptr(new Settings()); |
|
s_instance = ptr.toWeakRef(); |
|
return ptr; |
|
} |
|
return s_instance.toStrongRef(); |
|
} |
|
|
|
Notifications::Notifications(QObject *parent) |
|
: QSortFilterProxyModel(parent) |
|
, d(new Private(this)) |
|
{ |
|
// The proxy models are always the same, just with different |
|
// properties set whereas we want to avoid loading a source model |
|
// e.g. notifications or jobs when we're not actually using them |
|
d->initProxyModels(); |
|
|
|
// init source models when used from C++ |
|
QMetaObject::invokeMethod( |
|
this, |
|
[this] { |
|
d->initSourceModels(); |
|
}, |
|
Qt::QueuedConnection); |
|
} |
|
|
|
Notifications::~Notifications() = default; |
|
|
|
void Notifications::classBegin() |
|
{ |
|
} |
|
|
|
void Notifications::componentComplete() |
|
{ |
|
// init source models when used from QML |
|
d->initSourceModels(); |
|
} |
|
|
|
int Notifications::limit() const |
|
{ |
|
return d->limiterModel->limit(); |
|
} |
|
|
|
void Notifications::setLimit(int limit) |
|
{ |
|
d->limiterModel->setLimit(limit); |
|
} |
|
|
|
int Notifications::groupLimit() const |
|
{ |
|
return d->groupLimit; |
|
} |
|
|
|
void Notifications::setGroupLimit(int limit) |
|
{ |
|
if (d->groupLimit == limit) { |
|
return; |
|
} |
|
|
|
d->groupLimit = limit; |
|
if (d->groupCollapsingModel) { |
|
d->groupCollapsingModel->setLimit(limit); |
|
} |
|
Q_EMIT groupLimitChanged(); |
|
} |
|
|
|
bool Notifications::expandUnread() const |
|
{ |
|
return d->expandUnread; |
|
} |
|
|
|
void Notifications::setExpandUnread(bool expand) |
|
{ |
|
if (d->expandUnread == expand) { |
|
return; |
|
} |
|
|
|
d->expandUnread = expand; |
|
if (d->groupCollapsingModel) { |
|
d->groupCollapsingModel->setExpandUnread(expand); |
|
} |
|
Q_EMIT expandUnreadChanged(); |
|
} |
|
|
|
bool Notifications::showExpired() const |
|
{ |
|
return d->filterModel->showExpired(); |
|
} |
|
|
|
void Notifications::setShowExpired(bool show) |
|
{ |
|
d->filterModel->setShowExpired(show); |
|
} |
|
|
|
bool Notifications::showDismissed() const |
|
{ |
|
return d->filterModel->showDismissed(); |
|
} |
|
|
|
void Notifications::setShowDismissed(bool show) |
|
{ |
|
d->filterModel->setShowDismissed(show); |
|
} |
|
|
|
QStringList Notifications::blacklistedDesktopEntries() const |
|
{ |
|
return d->filterModel->blacklistedDesktopEntries(); |
|
} |
|
|
|
void Notifications::setBlacklistedDesktopEntries(const QStringList &blacklist) |
|
{ |
|
d->filterModel->setBlackListedDesktopEntries(blacklist); |
|
} |
|
|
|
QStringList Notifications::blacklistedNotifyRcNames() const |
|
{ |
|
return d->filterModel->blacklistedNotifyRcNames(); |
|
} |
|
|
|
void Notifications::setBlacklistedNotifyRcNames(const QStringList &blacklist) |
|
{ |
|
d->filterModel->setBlacklistedNotifyRcNames(blacklist); |
|
} |
|
|
|
QStringList Notifications::whitelistedDesktopEntries() const |
|
{ |
|
return d->filterModel->whitelistedDesktopEntries(); |
|
} |
|
|
|
void Notifications::setWhitelistedDesktopEntries(const QStringList &whitelist) |
|
{ |
|
d->filterModel->setWhiteListedDesktopEntries(whitelist); |
|
} |
|
|
|
QStringList Notifications::whitelistedNotifyRcNames() const |
|
{ |
|
return d->filterModel->whitelistedNotifyRcNames(); |
|
} |
|
|
|
void Notifications::setWhitelistedNotifyRcNames(const QStringList &whitelist) |
|
{ |
|
d->filterModel->setWhitelistedNotifyRcNames(whitelist); |
|
} |
|
|
|
bool Notifications::showNotifications() const |
|
{ |
|
return d->showNotifications; |
|
} |
|
|
|
void Notifications::setShowNotifications(bool show) |
|
{ |
|
if (d->showNotifications == show) { |
|
return; |
|
} |
|
|
|
d->showNotifications = show; |
|
d->initSourceModels(); |
|
Q_EMIT showNotificationsChanged(); |
|
} |
|
|
|
bool Notifications::showJobs() const |
|
{ |
|
return d->showJobs; |
|
} |
|
|
|
void Notifications::setShowJobs(bool show) |
|
{ |
|
if (d->showJobs == show) { |
|
return; |
|
} |
|
|
|
d->showJobs = show; |
|
d->initSourceModels(); |
|
Q_EMIT showJobsChanged(); |
|
} |
|
|
|
Notifications::Urgencies Notifications::urgencies() const |
|
{ |
|
return d->filterModel->urgencies(); |
|
} |
|
|
|
void Notifications::setUrgencies(Urgencies urgencies) |
|
{ |
|
d->filterModel->setUrgencies(urgencies); |
|
} |
|
|
|
Notifications::SortMode Notifications::sortMode() const |
|
{ |
|
return d->sortModel->sortMode(); |
|
} |
|
|
|
void Notifications::setSortMode(SortMode sortMode) |
|
{ |
|
d->sortModel->setSortMode(sortMode); |
|
} |
|
|
|
Qt::SortOrder Notifications::sortOrder() const |
|
{ |
|
return d->sortModel->sortOrder(); |
|
} |
|
|
|
void Notifications::setSortOrder(Qt::SortOrder sortOrder) |
|
{ |
|
d->sortModel->setSortOrder(sortOrder); |
|
} |
|
|
|
Notifications::GroupMode Notifications::groupMode() const |
|
{ |
|
return d->groupMode; |
|
} |
|
|
|
void Notifications::setGroupMode(GroupMode groupMode) |
|
{ |
|
if (d->groupMode != groupMode) { |
|
d->groupMode = groupMode; |
|
d->initProxyModels(); |
|
Q_EMIT groupModeChanged(); |
|
} |
|
} |
|
|
|
int Notifications::count() const |
|
{ |
|
return rowCount(QModelIndex()); |
|
} |
|
|
|
int Notifications::activeNotificationsCount() const |
|
{ |
|
return d->activeNotificationsCount; |
|
} |
|
|
|
int Notifications::expiredNotificationsCount() const |
|
{ |
|
return d->expiredNotificationsCount; |
|
} |
|
|
|
QDateTime Notifications::lastRead() const |
|
{ |
|
if (d->notificationsModel) { |
|
return d->notificationsModel->lastRead(); |
|
} |
|
return QDateTime(); |
|
} |
|
|
|
void Notifications::setLastRead(const QDateTime &lastRead) |
|
{ |
|
// TODO jobs could also be unread? |
|
if (d->notificationsModel) { |
|
d->notificationsModel->setLastRead(lastRead); |
|
} |
|
if (d->groupCollapsingModel) { |
|
d->groupCollapsingModel->setLastRead(lastRead); |
|
} |
|
} |
|
|
|
void Notifications::resetLastRead() |
|
{ |
|
setLastRead(QDateTime::currentDateTimeUtc()); |
|
} |
|
|
|
int Notifications::unreadNotificationsCount() const |
|
{ |
|
return d->unreadNotificationsCount; |
|
} |
|
|
|
int Notifications::activeJobsCount() const |
|
{ |
|
return d->activeJobsCount; |
|
} |
|
|
|
int Notifications::jobsPercentage() const |
|
{ |
|
return d->jobsPercentage; |
|
} |
|
|
|
QPersistentModelIndex Notifications::makePersistentModelIndex(const QModelIndex &idx) const |
|
{ |
|
return QPersistentModelIndex(idx); |
|
} |
|
|
|
void Notifications::expire(const QModelIndex &idx) |
|
{ |
|
switch (static_cast<Notifications::Type>(idx.data(Notifications::TypeRole).toInt())) { |
|
case Notifications::NotificationType: |
|
d->notificationsModel->expire(Private::notificationId(idx)); |
|
break; |
|
case Notifications::JobType: |
|
d->jobsModel->expire(Utils::mapToModel(idx, d->jobsModel.data())); |
|
break; |
|
default: |
|
Q_UNREACHABLE(); |
|
} |
|
} |
|
|
|
void Notifications::close(const QModelIndex &idx) |
|
{ |
|
if (idx.data(Notifications::IsGroupRole).toBool()) { |
|
const QModelIndex groupIdx = Utils::mapToModel(idx, d->groupingModel); |
|
if (!groupIdx.isValid()) { |
|
qCWarning(NOTIFICATIONMANAGER) << "Failed to find group model index for this item"; |
|
return; |
|
} |
|
|
|
Q_ASSERT(groupIdx.model() == d->groupingModel); |
|
|
|
const int childCount = d->groupingModel->rowCount(groupIdx); |
|
for (int i = childCount - 1; i >= 0; --i) { |
|
const QModelIndex childIdx = d->groupingModel->index(i, 0, groupIdx); |
|
close(childIdx); |
|
} |
|
return; |
|
} |
|
|
|
if (!idx.data(Notifications::ClosableRole).toBool()) { |
|
return; |
|
} |
|
|
|
switch (static_cast<Notifications::Type>(idx.data(Notifications::TypeRole).toInt())) { |
|
case Notifications::NotificationType: |
|
d->notificationsModel->close(Private::notificationId(idx)); |
|
break; |
|
case Notifications::JobType: |
|
d->jobsModel->close(Utils::mapToModel(idx, d->jobsModel.data())); |
|
break; |
|
default: |
|
Q_UNREACHABLE(); |
|
} |
|
} |
|
|
|
void Notifications::configure(const QModelIndex &idx) |
|
{ |
|
if (!d->notificationsModel) { |
|
return; |
|
} |
|
|
|
// For groups just configure the application, not the individual event |
|
if (Private::isGroup(idx)) { |
|
const QString desktopEntry = idx.data(Notifications::DesktopEntryRole).toString(); |
|
const QString notifyRcName = idx.data(Notifications::NotifyRcNameRole).toString(); |
|
|
|
d->notificationsModel->configure(desktopEntry, notifyRcName, QString() /*eventId*/); |
|
return; |
|
} |
|
|
|
d->notificationsModel->configure(Private::notificationId(idx)); |
|
} |
|
|
|
void Notifications::invokeDefaultAction(const QModelIndex &idx, InvokeBehavior behavior) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->invokeDefaultAction(Private::notificationId(idx), behavior); |
|
} |
|
} |
|
|
|
void Notifications::invokeAction(const QModelIndex &idx, const QString &actionId, InvokeBehavior behavior) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->invokeAction(Private::notificationId(idx), actionId, behavior); |
|
} |
|
} |
|
|
|
void Notifications::reply(const QModelIndex &idx, const QString &text, InvokeBehavior behavior) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->reply(Private::notificationId(idx), text, behavior); |
|
} |
|
} |
|
|
|
void Notifications::startTimeout(const QModelIndex &idx) |
|
{ |
|
startTimeout(Private::notificationId(idx)); |
|
} |
|
|
|
void Notifications::startTimeout(uint notificationId) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->startTimeout(notificationId); |
|
} |
|
} |
|
|
|
void Notifications::stopTimeout(const QModelIndex &idx) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->stopTimeout(Private::notificationId(idx)); |
|
} |
|
} |
|
|
|
void Notifications::suspendJob(const QModelIndex &idx) |
|
{ |
|
if (d->jobsModel) { |
|
d->jobsModel->suspend(Utils::mapToModel(idx, d->jobsModel.data())); |
|
} |
|
} |
|
|
|
void Notifications::resumeJob(const QModelIndex &idx) |
|
{ |
|
if (d->jobsModel) { |
|
d->jobsModel->resume(Utils::mapToModel(idx, d->jobsModel.data())); |
|
} |
|
} |
|
|
|
void Notifications::killJob(const QModelIndex &idx) |
|
{ |
|
if (d->jobsModel) { |
|
d->jobsModel->kill(Utils::mapToModel(idx, d->jobsModel.data())); |
|
} |
|
} |
|
|
|
void Notifications::clear(ClearFlags flags) |
|
{ |
|
if (d->notificationsModel) { |
|
d->notificationsModel->clear(flags); |
|
} |
|
if (d->jobsModel) { |
|
d->jobsModel->clear(flags); |
|
} |
|
} |
|
|
|
QModelIndex Notifications::groupIndex(const QModelIndex &idx) const |
|
{ |
|
if (idx.data(Notifications::IsGroupRole).toBool()) { |
|
return idx; |
|
} |
|
|
|
if (idx.data(Notifications::IsInGroupRole).toBool()) { |
|
QModelIndex groupingIdx = Utils::mapToModel(idx, d->groupingModel); |
|
return d->mapFromModel(groupingIdx.parent()); |
|
} |
|
|
|
qCWarning(NOTIFICATIONMANAGER) << "Cannot get group index for item that isn't a group or inside one"; |
|
return QModelIndex(); |
|
} |
|
|
|
void Notifications::collapseAllGroups() |
|
{ |
|
if (d->groupCollapsingModel) { |
|
d->groupCollapsingModel->collapseAll(); |
|
} |
|
} |
|
|
|
QVariant Notifications::data(const QModelIndex &index, int role) const |
|
{ |
|
return QSortFilterProxyModel::data(index, role); |
|
} |
|
|
|
bool Notifications::setData(const QModelIndex &index, const QVariant &value, int role) |
|
{ |
|
return QSortFilterProxyModel::setData(index, value, role); |
|
} |
|
|
|
bool Notifications::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const |
|
{ |
|
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); |
|
} |
|
|
|
bool Notifications::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const |
|
{ |
|
return QSortFilterProxyModel::lessThan(source_left, source_right); |
|
} |
|
|
|
int Notifications::rowCount(const QModelIndex &parent) const |
|
{ |
|
return QSortFilterProxyModel::rowCount(parent); |
|
} |
|
|
|
QHash<int, QByteArray> Notifications::roleNames() const |
|
{ |
|
return Utils::roleNames(); |
|
}
|
|
|