diff options
author | Bernd Weimer <bernd.weimer@qt.io> | 2023-06-30 08:47:27 +0200 |
---|---|---|
committer | Bernd Weimer <bernd.weimer@qt.io> | 2023-07-25 13:01:00 +0200 |
commit | 13c74e599394ed6c7305a5ca8f57456f763bb80f (patch) | |
tree | 6983331b622b45da06bd324573a47391fb1492de | |
parent | 8bdc93e39fe85e738c05b13b9af962a29a2bd06c (diff) |
Add NotificationModel QML type
The type is a proxy for the NotificationManager model and provides
the possibility to sort and filter it. Also improved the other proxy
models.
Fixes: QTBUG-114879
Pick-to: 6.6
Change-Id: Icf86e2a4a00fdbb296a97dd7ed4c1b9557a16ec8
Reviewed-by: Robert Griebl <robert.griebl@qt.io>
-rw-r--r-- | qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes | 41 | ||||
-rw-r--r-- | src/common-lib/utilities.cpp | 8 | ||||
-rw-r--r-- | src/common-lib/utilities.h | 3 | ||||
-rw-r--r-- | src/intent-server-lib/intentmodel.cpp | 27 | ||||
-rw-r--r-- | src/intent-server-lib/intentmodel.h | 2 | ||||
-rw-r--r-- | src/manager-lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/manager-lib/applicationmodel.cpp | 27 | ||||
-rw-r--r-- | src/manager-lib/applicationmodel.h | 2 | ||||
-rw-r--r-- | src/manager-lib/notificationmanager.cpp | 2 | ||||
-rw-r--r-- | src/manager-lib/notificationmodel.cpp | 264 | ||||
-rw-r--r-- | src/manager-lib/notificationmodel.h | 61 | ||||
-rw-r--r-- | src/tools/dumpqmltypes/dumpqmltypes.cpp | 2 | ||||
-rw-r--r-- | tests/auto/qml/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/notifications/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/auto/qml/notifications/tst_notifications.qml | 56 |
15 files changed, 464 insertions, 34 deletions
diff --git a/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes b/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes index 1b4b17b3..5c6e890c 100644 --- a/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes +++ b/qmltypes/QtApplicationManager/SystemUI/plugins.qmltypes @@ -592,6 +592,47 @@ Module { } } Component { + name: "NotificationModel" + exports: [ "QtApplicationManager.SystemUI/NotificationModel 2.2", "QtApplicationManager.SystemUI/NotificationModel 2.1", "QtApplicationManager.SystemUI/NotificationModel 2.0" ] + exportMetaObjectRevisions: [ 514, 513, 512 ] + prototype: "QObject" + Property { name: "count"; type: "int"; isReadonly: true; isFinal: true } + Property { name: "filterFunction"; type: "QJSValue"; isFinal: true } + Property { name: "sortFunction"; type: "QJSValue"; isFinal: true } + Signal { + name: "countChanged" + } + Signal { + name: "filterFunctionChanged" + } + Signal { + name: "sortFunctionChanged" + } + Method { + name: "indexOfNotification" + type: "int" + Parameter { name: "notificationId"; type: "uint" } + } + Method { + name: "indexOfNotification" + type: "int" + Parameter { name: "notification"; type: "Notification"; isPointer: true } + } + Method { + name: "mapToSource" + type: "int" + Parameter { name: "ourIndex"; type: "int" } + } + Method { + name: "mapFromSource" + type: "int" + Parameter { name: "sourceIndex"; type: "int" } + } + Method { + name: "invalidate" + } + } + Component { name: "NotificationManager" exports: [ "QtApplicationManager.SystemUI/NotificationManager 2.0" ] exportMetaObjectRevisions: [ 512 ] diff --git a/src/common-lib/utilities.cpp b/src/common-lib/utilities.cpp index 91645647..7c4e4282 100644 --- a/src/common-lib/utilities.cpp +++ b/src/common-lib/utilities.cpp @@ -10,6 +10,8 @@ #include <QCoreApplication> #include <QNetworkInterface> #include <QPluginLoader> +#include <QQmlContext> +#include <QQmlEngine> #include <qplatformdefs.h> #include "utilities.h" @@ -346,4 +348,10 @@ void validateIdForFilesystemUsage(const QString &id) Q_DECL_NOEXCEPT_EXPR(false throw Exception(Error::Parse, "must not consist of only white-space characters"); } +QJSEngine *getJSEngine(const QObject *obj) +{ + QQmlContext *context = QQmlEngine::contextForObject(obj); + return context ? reinterpret_cast<QJSEngine*>(context->engine()) : nullptr; +} + QT_END_NAMESPACE_AM diff --git a/src/common-lib/utilities.h b/src/common-lib/utilities.h index ed52ce4b..b803500e 100644 --- a/src/common-lib/utilities.h +++ b/src/common-lib/utilities.h @@ -20,6 +20,7 @@ #include <functional> QT_FORWARD_DECLARE_CLASS(QDir) +QT_FORWARD_DECLARE_CLASS(QJSEngine) QT_BEGIN_NAMESPACE_AM @@ -126,4 +127,6 @@ void closeAndClearFileDescriptors(QVector<int> &fdList); // make sure that the given id can be used as a filename void validateIdForFilesystemUsage(const QString &id) Q_DECL_NOEXCEPT_EXPR(false); +QJSEngine *getJSEngine(const QObject *obj); + QT_END_NAMESPACE_AM diff --git a/src/intent-server-lib/intentmodel.cpp b/src/intent-server-lib/intentmodel.cpp index a3ef2bcd..c5c82503 100644 --- a/src/intent-server-lib/intentmodel.cpp +++ b/src/intent-server-lib/intentmodel.cpp @@ -2,7 +2,6 @@ // Copyright (C) 2019 Luxoft Sweden AB // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only -#include <QQmlContext> #include <QQmlEngine> #include <QQmlInfo> #include <QJSEngine> @@ -13,6 +12,7 @@ #include "intentserver.h" #include "intentmodel.h" #include "intent.h" +#include "utilities.h" /*! @@ -49,6 +49,7 @@ } delegate: Image { + required property string icon source: icon } } @@ -127,10 +128,11 @@ bool IntentModel::filterAcceptsRow(int source_row, const QModelIndex &source_par { Q_UNUSED(source_parent) - if (!d->m_engine) - d->m_engine = getJSEngine(); - if (!d->m_engine) - qCWarning(LogSystem) << "IntentModel can't filter without a JavaScript engine"; + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogIntents) << "IntentModel can't filter without a JavaScript engine"; + } if (d->m_engine && d->m_filterFunction.isCallable()) { const QObject *intent = IntentServer::instance()->intent(source_row); @@ -143,10 +145,11 @@ bool IntentModel::filterAcceptsRow(int source_row, const QModelIndex &source_par bool IntentModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { - if (!d->m_engine) - d->m_engine = getJSEngine(); - if (!d->m_engine) - qCWarning(LogSystem) << "IntentModel can't sort without a JavaScript engine"; + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogIntents) << "IntentModel can't sort without a JavaScript engine"; + } if (d->m_engine && d->m_sortFunction.isCallable()) { const QObject *intent1 = IntentServer::instance()->intent(source_left.row()); @@ -247,12 +250,6 @@ void IntentModel::invalidate() QSortFilterProxyModel::invalidate(); } -QJSEngine *IntentModel::getJSEngine() const -{ - QQmlContext *context = QQmlEngine::contextForObject(this); - return context ? reinterpret_cast<QJSEngine*>(context->engine()) : nullptr; -} - QT_END_NAMESPACE_AM #include "moc_intentmodel.cpp" diff --git a/src/intent-server-lib/intentmodel.h b/src/intent-server-lib/intentmodel.h index 65109131..3aef1548 100644 --- a/src/intent-server-lib/intentmodel.h +++ b/src/intent-server-lib/intentmodel.h @@ -56,8 +56,6 @@ signals: void sortFunctionChanged(); private: - QJSEngine *getJSEngine() const; - IntentModelPrivate *d; }; diff --git a/src/manager-lib/CMakeLists.txt b/src/manager-lib/CMakeLists.txt index 2e4f3481..35bc83d9 100644 --- a/src/manager-lib/CMakeLists.txt +++ b/src/manager-lib/CMakeLists.txt @@ -23,6 +23,7 @@ qt_internal_add_module(AppManManagerPrivate inprocesssurfaceitem.cpp inprocesssurfaceitem.h intentaminterface.cpp intentaminterface.h notificationmanager.cpp notificationmanager.h + notificationmodel.cpp notificationmodel.h package.cpp package.h packagemanager.cpp packagemanager.h packagemanager_p.h plugincontainer.cpp plugincontainer.h diff --git a/src/manager-lib/applicationmodel.cpp b/src/manager-lib/applicationmodel.cpp index 9915b39f..04d7b8f1 100644 --- a/src/manager-lib/applicationmodel.cpp +++ b/src/manager-lib/applicationmodel.cpp @@ -3,7 +3,6 @@ // Copyright (C) 2018 Pelagicore AG // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only -#include <QQmlContext> #include <QQmlEngine> #include <QQmlInfo> #include <QJSEngine> @@ -14,6 +13,7 @@ #include "applicationmanager.h" #include "applicationmodel.h" #include "application.h" +#include "utilities.h" /*! @@ -49,6 +49,7 @@ } delegate: Image { + required property string icon source: icon } } @@ -135,10 +136,11 @@ bool ApplicationModel::filterAcceptsRow(int source_row, const QModelIndex &sourc { Q_UNUSED(source_parent) - if (!d->m_engine) - d->m_engine = getJSEngine(); - if (!d->m_engine) - qCWarning(LogSystem) << "ApplicationModel can't filter without a JavaScript engine"; + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogSystem) << "ApplicationModel can't filter without a JavaScript engine"; + } if (d->m_engine && d->m_filterFunction.isCallable()) { const QObject *app = ApplicationManager::instance()->application(source_row); @@ -151,10 +153,11 @@ bool ApplicationModel::filterAcceptsRow(int source_row, const QModelIndex &sourc bool ApplicationModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { - if (!d->m_engine) - d->m_engine = getJSEngine(); - if (!d->m_engine) - qCWarning(LogSystem) << "ApplicationModel can't sort without a JavaScript engine"; + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogSystem) << "ApplicationModel can't sort without a JavaScript engine"; + } if (d->m_engine && d->m_sortFunction.isCallable()) { const QObject *app1 = ApplicationManager::instance()->application(source_left.row()); @@ -260,12 +263,6 @@ void ApplicationModel::invalidate() QSortFilterProxyModel::invalidate(); } -QJSEngine *ApplicationModel::getJSEngine() const -{ - QQmlContext *context = QQmlEngine::contextForObject(this); - return context ? reinterpret_cast<QJSEngine*>(context->engine()) : nullptr; -} - QT_END_NAMESPACE_AM #include "moc_applicationmodel.cpp" diff --git a/src/manager-lib/applicationmodel.h b/src/manager-lib/applicationmodel.h index 37c163d7..8d8fc093 100644 --- a/src/manager-lib/applicationmodel.h +++ b/src/manager-lib/applicationmodel.h @@ -57,8 +57,6 @@ signals: void sortFunctionChanged(); private: - QJSEngine *getJSEngine() const; - ApplicationModelPrivate *d; }; diff --git a/src/manager-lib/notificationmanager.cpp b/src/manager-lib/notificationmanager.cpp index 667b64bc..fc0ddc0d 100644 --- a/src/manager-lib/notificationmanager.cpp +++ b/src/manager-lib/notificationmanager.cpp @@ -16,6 +16,7 @@ #include "qml-utilities.h" #include "dbus-utilities.h" #include "package.h" +#include "notificationmodel.h" /*! \qmltype NotificationManager @@ -230,6 +231,7 @@ NotificationManager *NotificationManager::createInstance() if (Q_UNLIKELY(s_instance)) qFatal("NotificationManager::createInstance() was called a second time."); + qmlRegisterType<NotificationModel>("QtApplicationManager.SystemUI", 2, 2, "NotificationModel"); qmlRegisterSingletonType<NotificationManager>("QtApplicationManager.SystemUI", 2, 0, "NotificationManager", &NotificationManager::instanceForQml); return s_instance = new NotificationManager(); diff --git a/src/manager-lib/notificationmodel.cpp b/src/manager-lib/notificationmodel.cpp new file mode 100644 index 00000000..1bb563c5 --- /dev/null +++ b/src/manager-lib/notificationmodel.cpp @@ -0,0 +1,264 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QQmlEngine> +#include <QQmlInfo> +#include <QJSEngine> +#include <QJSValueList> + +#include "global.h" +#include "logging.h" +#include "notificationmanager.h" +#include "notificationmodel.h" +#include "notification.h" +#include "utilities.h" + + +/*! + \qmltype NotificationModel + \inherits QSortFilterProxyModel + \ingroup system-ui-instantiable + \inqmlmodule QtApplicationManager.SystemUI + \brief A proxy model for the NotificationManager singleton. + + The NotificationModel type provides a customizable model that can be used to tailor the + NotificationManager model to your needs. The NotificationManager singleton is a model itself, + that includes all available notifications. In contrast, the NotificationModel supports filtering + and sorting. + + Since the NotificationModel is based on the NotificationManager model, the latter is referred + to as the \e source model. The NotificationModel includes the same \l {NotificationManager Roles} + {roles} as the NotificationManager model. + + \note If you require a model with all notifications, with no filtering whatsoever, you should + use the NotificationManager directly, as it has better performance. + + The following code snippet displays the summary of all notifications with a priority greater + than 5 in a list: + + \qml + import QtQuick + import QtApplicationManager.SystemUI + + ListView { + model: NotificationModel { + filterFunction: function(notification) { + return notification.priority > 5; + } + } + + Text { + required property string summary + text: summary + } + } + \endqml +*/ + +/*! + \qmlproperty int NotificationModel::count + \readonly + + Holds the number of notifications included in this model. +*/ + +/*! + \qmlproperty var NotificationModel::filterFunction + + A JavaScript function callback that is invoked for each notification in the NotificationManager + source model. This function gets one Notification parameter and must return a Boolean. + If the notification passed should be included in this model, then the function must return + \c true; \c false otherwise. + + If you need no filtering at all, you should set this property to an undefined (the default) or + null value. + + \note Whenever this function is changed, the filter is reevaluated. Changes in the source model + are also reflected. To force a complete reevaluation, call \l {NotificationModel::invalidate()} + {invalidate()}. +*/ + +/*! + \qmlproperty var NotificationModel::sortFunction + + A JavaScript function callback that is invoked to sort the notifications in this model. This + function gets two Notification parameters and must return a Boolean. If the first + notification should have a smaller index in this model than the second, the function must return + \c true; \c false otherwise. + + If you need no sorting at all, you should set this property to an undefined (the default) or + null value. + + \note Whenever this function is changed, the model is sorted. Changes in the source model are + also reflected. To force a complete reevaluation, call \l {NotificationModel::invalidate()} + {invalidate()}. +*/ + + +QT_BEGIN_NAMESPACE_AM + + +class NotificationModelPrivate +{ +public: + QJSEngine *m_engine = nullptr; + QJSValue m_filterFunction; + QJSValue m_sortFunction; +}; + + +NotificationModel::NotificationModel(QObject *parent) + : QSortFilterProxyModel(parent) + , d(new NotificationModelPrivate()) +{ + setSourceModel(NotificationManager::instance()); + + connect(this, &QAbstractItemModel::rowsInserted, this, &NotificationModel::countChanged); + connect(this, &QAbstractItemModel::rowsRemoved, this, &NotificationModel::countChanged); + connect(this, &QAbstractItemModel::layoutChanged, this, &NotificationModel::countChanged); + connect(this, &QAbstractItemModel::modelReset, this, &NotificationModel::countChanged); +} + +NotificationModel::~NotificationModel() +{ + delete d; +} + +int NotificationModel::count() const +{ + return rowCount(); +} + +bool NotificationModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + Q_UNUSED(source_parent) + + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogNotifications) << "NotificationModel can't filter without a JavaScript engine"; + } + + if (d->m_engine && d->m_filterFunction.isCallable()) { + const QVariantMap notification = NotificationManager::instance()->get(source_row); + QJSValueList args = { d->m_engine->toScriptValue(notification) }; + return d->m_filterFunction.call(args).toBool(); + } + + return true; +} + +bool NotificationModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const +{ + if (!d->m_engine) { + d->m_engine = getJSEngine(this); + if (!d->m_engine) + qCWarning(LogNotifications) << "NotificationModel can't sort without a JavaScript engine"; + } + + if (d->m_engine && d->m_sortFunction.isCallable()) { + const QVariantMap left = NotificationManager::instance()->get(source_left.row()); + const QVariantMap right = NotificationManager::instance()->get(source_right.row()); + QJSValueList args = { d->m_engine->toScriptValue(left), d->m_engine->toScriptValue(right) }; + return d->m_sortFunction.call(args).toBool(); + } + + return QSortFilterProxyModel::lessThan(source_left, source_right); +} + +QJSValue NotificationModel::filterFunction() const +{ + return d->m_filterFunction; +} + +void NotificationModel::setFilterFunction(const QJSValue &callback) +{ + if (!callback.isCallable() && !callback.isNull() && !callback.isUndefined()) { + qmlWarning(this) << "The filterFunction property of NotificationModel needs to be either " + "callable, or undefined/null to clear it."; + } + + if (!callback.equals(d->m_filterFunction)) { + d->m_filterFunction = callback; + emit filterFunctionChanged(); + invalidateFilter(); + } +} + +QJSValue NotificationModel::sortFunction() const +{ + return d->m_sortFunction; +} + +void NotificationModel::setSortFunction(const QJSValue &callback) +{ + if (!callback.isCallable() && !callback.isNull() && !callback.isUndefined()) { + qmlWarning(this) << "The sortFunction property of NotificationModel needs to be either " + "callable, or undefined/null to clear it."; + } + if (!callback.equals(d->m_sortFunction)) { + d->m_sortFunction = callback; + emit sortFunctionChanged(); + invalidate(); + sort(0); + } +} + +/*! + \qmlmethod int NotificationModel::indexOfNotification(int notificationId) + + Maps the notification corresponding to the given \a notificationId to its position within this + model. Returns \c -1 if the specified notification is invalid, or not part of this model. +*/ +int NotificationModel::indexOfNotification(uint notificationId) const +{ + int idx = NotificationManager::instance()->indexOfNotification(notificationId); + return idx != -1 ? mapFromSource(idx) : idx; +} + +/*! + \qmlmethod int NotificationModel::indexOfNotification(object notification) + + Maps the \a notification to its position within this model. Returns \c -1 if the specified + notification is invalid, or not part of this model. +*/ +int NotificationModel::indexOfNotification(Notification *notification) const +{ + return indexOfNotification(notification->notificationId()); +} + +/*! + \qmlmethod int NotificationModel::mapToSource(int index) + + Maps a notification's \a index in this model to the corresponding index in the + NotificationManager model. Returns \c -1 if the specified \a index is invalid. +*/ +int NotificationModel::mapToSource(int ourIndex) const +{ + return QSortFilterProxyModel::mapToSource(index(ourIndex, 0)).row(); +} + +/*! + \qmlmethod int NotificationModel::mapFromSource(int index) + + Maps a notification's \a index from the NotificationManager model to the corresponding index in + this model. Returns \c -1 if the specified \a index is invalid. +*/ +int NotificationModel::mapFromSource(int sourceIndex) const +{ + return QSortFilterProxyModel::mapFromSource(sourceModel()->index(sourceIndex, 0)).row(); +} + +/*! + \qmlmethod NotificationModel::invalidate() + + Forces a reevaluation of the model. +*/ +void NotificationModel::invalidate() +{ + QSortFilterProxyModel::invalidate(); +} + +QT_END_NAMESPACE_AM + +#include "moc_notificationmodel.cpp" diff --git a/src/manager-lib/notificationmodel.h b/src/manager-lib/notificationmodel.h new file mode 100644 index 00000000..307d58ac --- /dev/null +++ b/src/manager-lib/notificationmodel.h @@ -0,0 +1,61 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#pragma once + +#include <QtCore/QSortFilterProxyModel> +#include <QtQml/QJSValue> +#include <QtAppManCommon/global.h> + +QT_FORWARD_DECLARE_CLASS(QJSEngine); + +QT_BEGIN_NAMESPACE_AM + +class NotificationModelPrivate; +class Notification; + +class NotificationModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/NotificationModel 2.2") + Q_CLASSINFO("AM-QmlPrototype", "QObject") + + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) + Q_PROPERTY(QJSValue filterFunction READ filterFunction WRITE setFilterFunction NOTIFY filterFunctionChanged FINAL) + Q_PROPERTY(QJSValue sortFunction READ sortFunction WRITE setSortFunction NOTIFY sortFunctionChanged FINAL) + +public: + NotificationModel(QObject *parent = nullptr); + ~NotificationModel() override; + + int count() const; + + QJSValue filterFunction() const; + void setFilterFunction(const QJSValue &callback); + + QJSValue sortFunction() const; + void setSortFunction(const QJSValue &callback); + + Q_INVOKABLE int indexOfNotification(uint notificationId) const; + Q_INVOKABLE int indexOfNotification(QT_PREPEND_NAMESPACE_AM(Notification) *notification) const; + Q_INVOKABLE int mapToSource(int ourIndex) const; + Q_INVOKABLE int mapFromSource(int sourceIndex) const; + Q_INVOKABLE void invalidate(); + +protected: + using QSortFilterProxyModel::mapToSource; + using QSortFilterProxyModel::mapFromSource; + + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; + +signals: + void countChanged(); + void filterFunctionChanged(); + void sortFunctionChanged(); + +private: + NotificationModelPrivate *d; +}; + +QT_END_NAMESPACE_AM diff --git a/src/tools/dumpqmltypes/dumpqmltypes.cpp b/src/tools/dumpqmltypes/dumpqmltypes.cpp index 84b83b7a..6355523c 100644 --- a/src/tools/dumpqmltypes/dumpqmltypes.cpp +++ b/src/tools/dumpqmltypes/dumpqmltypes.cpp @@ -14,6 +14,7 @@ #include <QtAppManManager/notificationmanager.h> #include <QtAppManNotification/notification.h> #include <QtAppManManager/notificationmanager.h> +#include <QtAppManManager/notificationmodel.h> #include <QtAppManManager/qmlinprocessapplicationinterface.h> #include <QtAppManWindow/windowmanager.h> #include <QtAppManWindow/window.h> @@ -50,6 +51,7 @@ static const QVector<const QMetaObject *> all = { &ApplicationInstaller::staticMetaObject, &PackageManager::staticMetaObject, &NotificationManager::staticMetaObject, + &NotificationModel::staticMetaObject, &Application::staticMetaObject, &AbstractRuntime::staticMetaObject, &AbstractContainer::staticMetaObject, diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt index efd57d78..3399e236 100644 --- a/tests/auto/qml/CMakeLists.txt +++ b/tests/auto/qml/CMakeLists.txt @@ -20,6 +20,7 @@ add_subdirectory(lifecycle) add_subdirectory(resources) add_subdirectory(keyinput) add_subdirectory(monitoring) +add_subdirectory(notifications) if (QT_FEATURE_am_multi_process) add_subdirectory(crash) add_subdirectory(processtitle) diff --git a/tests/auto/qml/notifications/CMakeLists.txt b/tests/auto/qml/notifications/CMakeLists.txt new file mode 100644 index 00000000..312616ea --- /dev/null +++ b/tests/auto/qml/notifications/CMakeLists.txt @@ -0,0 +1 @@ +qt_am_internal_add_qml_test(tst_notifications TEST_FILE tst_notifications.qml) diff --git a/tests/auto/qml/notifications/tst_notifications.qml b/tests/auto/qml/notifications/tst_notifications.qml new file mode 100644 index 00000000..a6e9ede4 --- /dev/null +++ b/tests/auto/qml/notifications/tst_notifications.qml @@ -0,0 +1,56 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtTest +import QtApplicationManager.SystemUI + +TestCase { + id: testCase + name: "Notifications" + + Component { + id: notificationComponent + Notification {} + } + + NotificationModel { + id: notificationModel + sortFunction: function(ln, rn) { return ln.priority < rn.priority; } + } + + SignalSpy { + id: notificationModelCountSpy + target: notificationModel + signalName: "countChanged" + } + + function test_notificationModel() { + compare(notificationModel.count, 0); + + let ntfc = []; + for (let i = 0; i < 3; i++) { + ntfc[i] = notificationComponent.createObject(testCase, { summary: `N${i}`, sticky: true }); + ntfc[i].priority = i === 1 ? 7 : i; + notificationModelCountSpy.clear(); + ntfc[i].show(); + notificationModelCountSpy.wait(1000 * AmTest.timeoutFactor); + compare(notificationModel.count, i + 1); + } + + compare(notificationModel.indexOfNotification(ntfc[0].notificationId), 0); + compare(notificationModel.indexOfNotification(ntfc[1]), 2); + compare(notificationModel.indexOfNotification(ntfc[2].notificationId), 1); + + notificationModelCountSpy.clear(); + notificationModel.filterFunction = function(n) { return n.summary !== "N0"; }; + + notificationModelCountSpy.wait(1000 * AmTest.timeoutFactor); + compare(notificationModel.count, 2); + compare(notificationModel.indexOfNotification(ntfc[2]), 0); + + ntfc[1].summary = "N0"; + notificationModelCountSpy.wait(1000 * AmTest.timeoutFactor); + compare(notificationModel.count, 1); + } +} |