Commit e8702822 authored by Konrad Materka's avatar Konrad Materka
Browse files

[applets/systemtray] Use QAbstractListModel

Rewrite model to use QAbstractListModel instead of QStandardItemModel
parent b529ec7a
...@@ -30,5 +30,6 @@ install(TARGETS org.kde.plasma.private.systemtray DESTINATION ${KDE_INSTALL_PLUG ...@@ -30,5 +30,6 @@ install(TARGETS org.kde.plasma.private.systemtray DESTINATION ${KDE_INSTALL_PLUG
add_subdirectory(container) add_subdirectory(container)
if(BUILD_TESTING) if(BUILD_TESTING)
add_subdirectory(autotests)
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
include(ECMAddTests)
set(systemtraymodel_test_SRCS
../systemtraymodel.cpp
../sortedsystemtraymodel.cpp
)
ecm_qt_declare_logging_category(systemtraymodel_test_SRCS HEADER debug.h
IDENTIFIER SYSTEM_TRAY
CATEGORY_NAME kde.systemtray
DEFAULT_SEVERITY Info)
add_library(systemtraymodel_test STATIC ${systemtraymodel_test_SRCS})
target_link_libraries(systemtraymodel_test
Qt5::Core
Qt5::Quick
KF5::Plasma
KF5::I18n
KF5::ItemModels
KF5::CoreAddons
)
ecm_add_tests(systemtraymodeltest.cpp
LINK_LIBRARIES systemtraymodel_test
Qt5::Test
)
[Desktop Entry]
Name=Device Notifier
Name[pl]=Powiadomienia o urządzeniach
Comment=Notifications and access for new devices
Comment[pl]=Powiadamia i daje dostęp do nowych urządzeń
Icon=device-notifier
Type=Service
X-KDE-ServiceTypes=Plasma/Applet
X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/devicenotifier.qml
X-Plasma-NotificationArea=true
X-Plasma-NotificationAreaCategory=Hardware
X-Plasma-Provides=org.kde.plasma.removabledevices
X-KDE-PluginInfo-Author=Viranch Mehta, Jacopo De Simoi
X-KDE-PluginInfo-Email=wilderkde@gmail.com
X-KDE-PluginInfo-Name=org.kde.plasma.devicenotifier.test
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=https://userbase.kde.org/Plasma/DeviceNotifier
X-KDE-PluginInfo-Category=System Information
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-License=GPL-2.0+
X-KDE-PluginInfo-EnabledByDefault=true
[Desktop Entry]
Name=Media Player
Name[pl]=Odtwarzacz multimedialny
Comment=Media Player Controls
Comment[pl]=Obsługa odtwarzacza multimedialnego
Icon=applications-multimedia
Type=Service
X-KDE-ServiceTypes=Plasma/Applet
X-KDE-PluginInfo-Author=Sebastian Kügler
X-KDE-PluginInfo-Category=Multimedia
X-KDE-PluginInfo-Depends=
X-KDE-PluginInfo-Email=sebas@kde.org
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-PluginInfo-License=GPL-2.0+
X-KDE-PluginInfo-Name=org.kde.plasma.mediacontroller.test
X-KDE-PluginInfo-Version=1.0
X-KDE-PluginInfo-Website=https://www.kde.org/plasma-desktop
X-Plasma-StandAloneApp=true
X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/main.qml
X-Plasma-NotificationArea=true
X-Plasma-NotificationAreaCategory=ApplicationStatus
X-Plasma-Provides=org.kde.plasma.multimediacontrols
X-Plasma-DBusActivationService=org.mpris.MediaPlayer2.*
/*
* Copyright 2020 Konrad Materka <materka@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) version 3, or any
* later version accepted by the membership of KDE e.V. (or its
* successor approved by the membership of KDE e.V.), which shall
* act as a proxy defined in Section 6 of version 3 of the license.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QtTest>
#include <Plasma/Applet>
#include <Plasma/DataEngine>
#include <Plasma/PluginLoader>
#include "../systemtraymodel.h"
class SystemTrayModelTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void init();
void testPlasmoidModel();
};
void SystemTrayModelTest::init()
{
QLocale::setDefault(QLocale("en_US"));
qunsetenv("LANGUAGE");
qunsetenv("LC_ALL");
qunsetenv("LC_MESSAGES");
qunsetenv("LANG");
}
void SystemTrayModelTest::testPlasmoidModel()
{
//given: sample plugin meta data
QList<KPluginMetaData> list;
list.append(KPluginMetaData(QFINDTESTDATA("data/mediacontroller/metadata.desktop")));
list.append(KPluginMetaData(QFINDTESTDATA("data/devicenotifier/metadata.desktop")));
//when: model is initialized
PlasmoidModel *model = new PlasmoidModel();
model->init(list);
//expect: passes consistency tests
new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::Fatal);
//and expect: correct model size
QCOMPARE(model->rowCount(), 2);
QCOMPARE(model->roleNames().size(), 10);
//and expect: correct data returned
QModelIndex idx = model->index(0, 0);
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Media Player (Automatic load)");
QVERIFY(model->data(idx, Qt::DecorationRole).isValid());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).toString(), "Plasmoid");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), "org.kde.plasma.mediacontroller.test");
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "ApplicationStatus");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Status)), QVariant(Plasma::Types::ItemStatus::UnknownStatus));
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::HiddenStatus));
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
idx = model->index(1, 0);
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Device Notifier");
QVERIFY(model->data(idx, Qt::DecorationRole).isValid());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).toString(), "Plasmoid");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemId)).toString(), "org.kde.plasma.devicenotifier.test");
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Category)).toString(), "Hardware");
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::Status)), QVariant(Plasma::Types::ItemStatus::UnknownStatus));
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::HiddenStatus));
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
//when: language is changed
QLocale::setDefault(QLocale("pl_PL"));
qputenv("LANG", "pl_PL.UTF-8");
qputenv("LC_MESSAGES", "pl_PL.UTF-8");
//then expect: translated data returned
QCOMPARE(model->data(idx, Qt::DisplayRole).toString(), "Powiadomienia o urz\u0105dzeniach");
//when: applet added
model->addApplet(new Plasma::Applet(list.at(1)));
//then: applet can be rendered
QVERIFY(model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QVERIFY(model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
QCOMPARE(model->data(idx, static_cast<int>(BaseModel::BaseRole::EffectiveStatus)), QVariant(Plasma::Types::ItemStatus::ActiveStatus));
//and when: applet removed
model->removeApplet(new Plasma::Applet(list.at(1)));
//then: applet cannot be rendered anymore
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::CanRender)).toBool());
QVERIFY(!model->data(idx, static_cast<int>(PlasmoidModel::Role::HasApplet)).toBool());
//and when: invalid index
idx = model->index(4, 0);
//then: empty value
QVERIFY(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).isNull());
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).isValid());
idx = model->index(1, 1);
QVERIFY(model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).isNull());
QVERIFY(!model->data(idx, static_cast<int>(BaseModel::BaseRole::ItemType)).isValid());
delete model;
}
QTEST_MAIN(SystemTrayModelTest)
#include "systemtraymodeltest.moc"
...@@ -54,10 +54,10 @@ AbstractItem { ...@@ -54,10 +54,10 @@ AbstractItem {
onClicked: { onClicked: {
var pos = plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y); var pos = plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y);
var service = model.Service;
switch (mouse.button) { switch (mouse.button) {
case Qt.LeftButton: case Qt.LeftButton:
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var operation = service.operationDescription("Activate"); var operation = service.operationDescription("Activate");
operation.x = pos.x; operation.x = pos.x;
operation.y = pos.y; operation.y = pos.y;
...@@ -76,7 +76,6 @@ AbstractItem { ...@@ -76,7 +76,6 @@ AbstractItem {
break; break;
case Qt.MiddleButton: case Qt.MiddleButton:
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var operation = service.operationDescription("SecondaryActivate"); var operation = service.operationDescription("SecondaryActivate");
operation.x = pos.x; operation.x = pos.x;
...@@ -88,7 +87,7 @@ AbstractItem { ...@@ -88,7 +87,7 @@ AbstractItem {
} }
function openContextMenu(pos) { function openContextMenu(pos) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource); var service = model.Service;
var operation = service.operationDescription("ContextMenu"); var operation = service.operationDescription("ContextMenu");
operation.x = pos.x; operation.x = pos.x;
operation.y = pos.y; operation.y = pos.y;
...@@ -102,14 +101,14 @@ AbstractItem { ...@@ -102,14 +101,14 @@ AbstractItem {
onWheel: { onWheel: {
//don't send activateVertScroll with a delta of 0, some clients seem to break (kmix) //don't send activateVertScroll with a delta of 0, some clients seem to break (kmix)
if (wheel.angleDelta.y !== 0) { if (wheel.angleDelta.y !== 0) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource); var service = model.Service;
var operation = service.operationDescription("Scroll"); var operation = service.operationDescription("Scroll");
operation.delta =wheel.angleDelta.y; operation.delta =wheel.angleDelta.y;
operation.direction = "Vertical"; operation.direction = "Vertical";
service.startOperationCall(operation); service.startOperationCall(operation);
} }
if (wheel.angleDelta.x !== 0) { if (wheel.angleDelta.x !== 0) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource); var service = model.Service;
var operation = service.operationDescription("Scroll"); var operation = service.operationDescription("Scroll");
operation.delta =wheel.angleDelta.x; operation.delta =wheel.angleDelta.x;
operation.direction = "Horizontal"; operation.direction = "Horizontal";
......
...@@ -303,11 +303,6 @@ bool SystemTray::isSystemTrayApplet(const QString &appletId) ...@@ -303,11 +303,6 @@ bool SystemTray::isSystemTrayApplet(const QString &appletId)
return m_systrayApplets.contains(appletId); return m_systrayApplets.contains(appletId);
} }
Plasma::Service *SystemTray::serviceForSource(const QString &source)
{
return m_statusNotifierModel->serviceForSource(source);
}
void SystemTray::restoreContents(KConfigGroup &group) void SystemTray::restoreContents(KConfigGroup &group)
{ {
QStringList newKnownItems; QStringList newKnownItems;
...@@ -436,6 +431,7 @@ SystemTrayModel *SystemTray::systemTrayModel() ...@@ -436,6 +431,7 @@ SystemTrayModel *SystemTray::systemTrayModel()
m_systemTrayModel = new SystemTrayModel(this); m_systemTrayModel = new SystemTrayModel(this);
PlasmoidModel *currentPlasmoidsModel = new PlasmoidModel(m_systemTrayModel); PlasmoidModel *currentPlasmoidsModel = new PlasmoidModel(m_systemTrayModel);
currentPlasmoidsModel->init(Plasma::PluginLoader::self()->listAppletMetaData(QString()));
connect(this, &SystemTray::appletAdded, currentPlasmoidsModel, &PlasmoidModel::addApplet); connect(this, &SystemTray::appletAdded, currentPlasmoidsModel, &PlasmoidModel::addApplet);
connect(this, &SystemTray::appletRemoved, currentPlasmoidsModel, &PlasmoidModel::removeApplet); connect(this, &SystemTray::appletRemoved, currentPlasmoidsModel, &PlasmoidModel::removeApplet);
connect(this, &SystemTray::configurationChanged, currentPlasmoidsModel, &PlasmoidModel::onConfigurationChanged); connect(this, &SystemTray::configurationChanged, currentPlasmoidsModel, &PlasmoidModel::onConfigurationChanged);
......
...@@ -87,12 +87,6 @@ public: ...@@ -87,12 +87,6 @@ public:
Q_INVOKABLE bool isSystemTrayApplet(const QString &appletId); Q_INVOKABLE bool isSystemTrayApplet(const QString &appletId);
/**
* @returns a Plasma::Service given a source name
* @param source source name we want a service of
*/
Q_INVOKABLE Plasma::Service *serviceForSource(const QString &source);
private Q_SLOTS: private Q_SLOTS:
void serviceNameFetchFinished(QDBusPendingCallWatcher* watcher); void serviceNameFetchFinished(QDBusPendingCallWatcher* watcher);
......
This diff is collapsed.
...@@ -20,17 +20,20 @@ ...@@ -20,17 +20,20 @@
#ifndef SYSTEMTRAYMODEL_H #ifndef SYSTEMTRAYMODEL_H
#define SYSTEMTRAYMODEL_H #define SYSTEMTRAYMODEL_H
#include <QStandardItemModel> #include <QAbstractListModel>
#include <QList>
#include <KCoreAddons/KPluginMetaData>
#include <KItemModels/KConcatenateRowsProxyModel> #include <KItemModels/KConcatenateRowsProxyModel>
#include <Plasma/DataEngineConsumer> #include <Plasma/DataEngineConsumer>
#include <Plasma/DataEngine> #include <Plasma/DataEngine>
namespace Plasma { namespace Plasma {
class Applet; class Applet;
class PluginLoader;
} }
class BaseModel: public QStandardItemModel class BaseModel: public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
public: public:
...@@ -51,15 +54,10 @@ public: ...@@ -51,15 +54,10 @@ public:
public slots: public slots:
void onConfigurationChanged(const KConfigGroup &config); void onConfigurationChanged(const KConfigGroup &config);
private slots: protected:
void onRowsInserted(const QModelIndex &parent, int first, int last); Plasma::Types::ItemStatus calculateEffectiveStatus(bool canRender, Plasma::Types::ItemStatus status, QString itemId) const;
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
private: private:
void updateEffectiveStatus(QStandardItem *dataItem);
Plasma::Types::ItemStatus calculateEffectiveStatus(QStandardItem *dataItem);
Plasma::Types::ItemStatus readStatus(QStandardItem *dataItem) const;
bool m_showAllItems; bool m_showAllItems;
QStringList m_shownItems; QStringList m_shownItems;
QStringList m_hiddenItems; QStringList m_hiddenItems;
...@@ -76,11 +74,26 @@ public: ...@@ -76,11 +74,26 @@ public:
explicit PlasmoidModel(QObject *parent = nullptr); explicit PlasmoidModel(QObject *parent = nullptr);
void init(const QList<KPluginMetaData> appletMetaDataList);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
public slots: public slots:
void addApplet(Plasma::Applet *applet); void addApplet(Plasma::Applet *applet);
void removeApplet(Plasma::Applet *applet); void removeApplet(Plasma::Applet *applet);
private:
struct Item {
KPluginMetaData pluginMetaData;
Plasma::Applet *applet = nullptr;
};
void appendRow(const KPluginMetaData &pluginMetaData);
int indexOfPluginId(const QString &pluginId) const;
QVector<Item> m_items;
}; };
class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer { class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer {
...@@ -88,6 +101,7 @@ class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer ...@@ -88,6 +101,7 @@ class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer
public: public:
enum class Role { enum class Role {
DataEngineSource = static_cast<int>(BaseModel::BaseRole::LastBaseRole) + 100, DataEngineSource = static_cast<int>(BaseModel::BaseRole::LastBaseRole) + 100,
Service,
AttentionIcon, AttentionIcon,
AttentionIconName, AttentionIconName,
AttentionMovieName, AttentionMovieName,
...@@ -105,23 +119,27 @@ public: ...@@ -105,23 +119,27 @@ public:
WindowId WindowId
}; };
StatusNotifierModel(QObject* parent); StatusNotifierModel(QObject* parent = nullptr);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
Plasma::Service *serviceForSource(const QString &source);
public slots: public slots:
void addSource(const QString &source); void addSource(const QString &source);
void removeSource(const QString &source); void removeSource(const QString &source);
void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data); void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data);
private: private:
void updateItemData(QStandardItem *dataItem, const Plasma::DataEngine::Data &data, const Role role); struct Item {
QString source;
Plasma::Service *service = nullptr;
};
int indexOfSource(const QString &source) const;
Plasma::DataEngine *m_dataEngine = nullptr; Plasma::DataEngine *m_dataEngine = nullptr;
QStringList m_sources; QVector<Item> m_items;
QHash<QString, Plasma::Service *> m_services;
}; };
class SystemTrayModel : public KConcatenateRowsProxyModel class SystemTrayModel : public KConcatenateRowsProxyModel
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment