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
add_subdirectory(container)
if(BUILD_TESTING)
add_subdirectory(autotests)
add_subdirectory(tests)
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 {
onClicked: {
var pos = plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y);
var service = model.Service;
switch (mouse.button) {
case Qt.LeftButton:
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var operation = service.operationDescription("Activate");
operation.x = pos.x;
operation.y = pos.y;
......@@ -76,7 +76,6 @@ AbstractItem {
break;
case Qt.MiddleButton:
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var operation = service.operationDescription("SecondaryActivate");
operation.x = pos.x;
......@@ -88,7 +87,7 @@ AbstractItem {
}
function openContextMenu(pos) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var service = model.Service;
var operation = service.operationDescription("ContextMenu");
operation.x = pos.x;
operation.y = pos.y;
......@@ -102,14 +101,14 @@ AbstractItem {
onWheel: {
//don't send activateVertScroll with a delta of 0, some clients seem to break (kmix)
if (wheel.angleDelta.y !== 0) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var service = model.Service;
var operation = service.operationDescription("Scroll");
operation.delta =wheel.angleDelta.y;
operation.direction = "Vertical";
service.startOperationCall(operation);
}
if (wheel.angleDelta.x !== 0) {
var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource);
var service = model.Service;
var operation = service.operationDescription("Scroll");
operation.delta =wheel.angleDelta.x;
operation.direction = "Horizontal";
......
......@@ -303,11 +303,6 @@ bool SystemTray::isSystemTrayApplet(const QString &appletId)
return m_systrayApplets.contains(appletId);
}
Plasma::Service *SystemTray::serviceForSource(const QString &source)
{
return m_statusNotifierModel->serviceForSource(source);
}
void SystemTray::restoreContents(KConfigGroup &group)
{
QStringList newKnownItems;
......@@ -436,6 +431,7 @@ SystemTrayModel *SystemTray::systemTrayModel()
m_systemTrayModel = new SystemTrayModel(this);
PlasmoidModel *currentPlasmoidsModel = new PlasmoidModel(m_systemTrayModel);
currentPlasmoidsModel->init(Plasma::PluginLoader::self()->listAppletMetaData(QString()));
connect(this, &SystemTray::appletAdded, currentPlasmoidsModel, &PlasmoidModel::addApplet);
connect(this, &SystemTray::appletRemoved, currentPlasmoidsModel, &PlasmoidModel::removeApplet);
connect(this, &SystemTray::configurationChanged, currentPlasmoidsModel, &PlasmoidModel::onConfigurationChanged);
......
......@@ -87,12 +87,6 @@ public:
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:
void serviceNameFetchFinished(QDBusPendingCallWatcher* watcher);
......
......@@ -20,6 +20,7 @@
#include "systemtraymodel.h"
#include "debug.h"
#include <QIcon>
#include <QQuickItem>
#include <Plasma/Applet>
......@@ -30,25 +31,23 @@
#include <KLocalizedString>
BaseModel::BaseModel(QObject *parent)
: QStandardItemModel(parent),
: QAbstractListModel(parent),
m_showAllItems(false)
{
connect(this, &BaseModel::rowsInserted, this, &BaseModel::onRowsInserted);
connect(this, &BaseModel::dataChanged, this, &BaseModel::onDataChanged);
}
QHash<int, QByteArray> BaseModel::roleNames() const
{
QHash<int, QByteArray> roles = QStandardItemModel::roleNames();
roles.insert(static_cast<int>(BaseRole::ItemType), QByteArrayLiteral("itemType"));
roles.insert(static_cast<int>(BaseRole::ItemId), QByteArrayLiteral("itemId"));
roles.insert(static_cast<int>(BaseRole::CanRender), QByteArrayLiteral("canRender"));
roles.insert(static_cast<int>(BaseRole::Category), QByteArrayLiteral("category"));
roles.insert(static_cast<int>(BaseRole::Status), QByteArrayLiteral("status"));
roles.insert(static_cast<int>(BaseRole::EffectiveStatus), QByteArrayLiteral("effectiveStatus"));
return roles;
return {
{Qt::DisplayRole, QByteArrayLiteral("display")},
{Qt::DecorationRole, QByteArrayLiteral("decoration")},
{static_cast<int>(BaseRole::ItemType), QByteArrayLiteral("itemType")},
{static_cast<int>(BaseRole::ItemId), QByteArrayLiteral("itemId")},
{static_cast<int>(BaseRole::CanRender), QByteArrayLiteral("canRender")},
{static_cast<int>(BaseRole::Category), QByteArrayLiteral("category")},
{static_cast<int>(BaseRole::Status), QByteArrayLiteral("status")},
{static_cast<int>(BaseRole::EffectiveStatus), QByteArrayLiteral("effectiveStatus")}
};
}
void BaseModel::onConfigurationChanged(const KConfigGroup &config)
......@@ -64,53 +63,20 @@ void BaseModel::onConfigurationChanged(const KConfigGroup &config)
m_hiddenItems = generalGroup.readEntry("hiddenItems", QStringList());
for (int i = 0; i < rowCount(); i++) {
QStandardItem *dataItem = item(i);
updateEffectiveStatus(dataItem);
}
}
void BaseModel::onRowsInserted(const QModelIndex &parent, int first, int last)
{
if (parent.isValid()) {
return;
}
for (int i = first; i <= last; ++i) {
QStandardItem *dataItem = item(i);
updateEffectiveStatus(dataItem);
}
}
void BaseModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
if (roles.contains(static_cast<int>(BaseRole::Status)) || roles.contains(static_cast<int>(BaseRole::CanRender))) {
for (int i = topLeft.row(); i <= bottomRight.row(); i++) {
QStandardItem *dataItem = item(i);
updateEffectiveStatus(dataItem);
}
dataChanged(index(i, 0), index(i, 0), {static_cast<int>(BaseModel::BaseRole::EffectiveStatus)});
}
}
void BaseModel::updateEffectiveStatus(QStandardItem *dataItem)
Plasma::Types::ItemStatus BaseModel::calculateEffectiveStatus(bool canRender, Plasma::Types::ItemStatus status, QString itemId) const
{
Plasma::Types::ItemStatus status = calculateEffectiveStatus(dataItem);
dataItem->setData(status, static_cast<int>(BaseModel::BaseRole::EffectiveStatus));
}
Plasma::Types::ItemStatus BaseModel::calculateEffectiveStatus(QStandardItem *dataItem)
{
bool canRender = dataItem->data(static_cast<int>(BaseRole::CanRender)).toBool();
if (!canRender) {
return Plasma::Types::ItemStatus::HiddenStatus;
}
Plasma::Types::ItemStatus status = readStatus(dataItem);
if (status == Plasma::Types::ItemStatus::HiddenStatus) {
return Plasma::Types::ItemStatus::HiddenStatus;
}
QString itemId = dataItem->data(static_cast<int>(BaseRole::ItemId)).toString();
bool forcedShown = m_showAllItems || m_shownItems.contains(itemId);
bool forcedHidden = m_hiddenItems.contains(itemId);
......@@ -121,15 +87,6 @@ Plasma::Types::ItemStatus BaseModel::calculateEffectiveStatus(QStandardItem *dat
}
}
Plasma::Types::ItemStatus BaseModel::readStatus(QStandardItem *dataItem) const
{
QVariant statusData = dataItem->data(static_cast<int>(BaseRole::Status));
if (statusData.isValid()) {
return statusData.value<Plasma::Types::ItemStatus>();
} else {
return Plasma::Types::ItemStatus::UnknownStatus;
}
}
static QString plasmoidCategoryForMetadata(const KPluginMetaData &metadata)
{
......@@ -147,26 +104,77 @@ static QString plasmoidCategoryForMetadata(const KPluginMetaData &metadata)
PlasmoidModel::PlasmoidModel(QObject *parent) : BaseModel(parent)
{
for (const auto &info : Plasma::PluginLoader::self()->listAppletMetaData(QString())) {
}
void PlasmoidModel::init(const QList<KPluginMetaData> appletMetaDataList)
{
for (const auto &info : appletMetaDataList) {
if (!info.isValid() || info.value(QStringLiteral("X-Plasma-NotificationArea")) != "true") {
continue;
}
appendRow(info);
}
}
QVariant PlasmoidModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid)) {
return QVariant();
}
const PlasmoidModel::Item &item = m_items[index.row()];
const KPluginMetaData &pluginMetaData = item.pluginMetaData;
const Plasma::Applet *applet = item.applet;
if (role <= Qt::UserRole) {
switch (role) {
case Qt::DisplayRole: {
const QString dbusactivation = pluginMetaData.value(QStringLiteral("X-Plasma-DBusActivationService"));
if (dbusactivation.isEmpty()) {
return pluginMetaData.name();
} else {
return i18nc("Suffix added to the applet name if the applet is autoloaded via DBus activation",
"%1 (Automatic load)", pluginMetaData.name());
}
}
case Qt::DecorationRole: {
QIcon icon = QIcon::fromTheme(pluginMetaData.iconName());
return icon.isNull() ? QVariant() : icon;
}
default:
return QVariant();
}
}
QString name = info.name();
const QString dbusactivation = info.value(QStringLiteral("X-Plasma-DBusActivationService"));
if (!dbusactivation.isEmpty()) {
name += i18n(" (Automatic load)");
if (role < static_cast<int>(Role::Applet)) {
Plasma::Types::ItemStatus status = Plasma::Types::ItemStatus::UnknownStatus;
if (applet) {
status = applet->status();
}
QStandardItem *item = new QStandardItem(QIcon::fromTheme(info.iconName()), name);
item->setData(info.pluginId(), static_cast<int>(BaseModel::BaseRole::ItemId));
item->setData(QStringLiteral("Plasmoid"), static_cast<int>(BaseModel::BaseRole::ItemType));
item->setData(false, static_cast<int>(BaseModel::BaseRole::CanRender));
item->setData(plasmoidCategoryForMetadata(info), static_cast<int>(BaseModel::BaseRole::Category));
item->setData(false, static_cast<int>(Role::HasApplet));
appendRow(item);
switch (static_cast<BaseRole>(role)) {
case BaseRole::ItemType: return QStringLiteral("Plasmoid");
case BaseRole::ItemId: return pluginMetaData.pluginId();
case BaseRole::CanRender: return applet != nullptr;
case BaseRole::Category: return plasmoidCategoryForMetadata(pluginMetaData);
case BaseRole::Status: return status;
case BaseRole::EffectiveStatus: return calculateEffectiveStatus(applet != nullptr, status, pluginMetaData.pluginId());
default: return QVariant();
}
}
switch (static_cast<Role>(role)) {
case Role::Applet: return applet ? applet->property("_plasma_graphicObject") : QVariant();
case Role::HasApplet: return applet != nullptr;
default: return QVariant();
}
}
int PlasmoidModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_items.size();
}
QHash<int, QByteArray> PlasmoidModel::roleNames() const
{
QHash<int, QByteArray> roles = BaseModel::roleNames();
......@@ -180,55 +188,56 @@ QHash<int, QByteArray> PlasmoidModel::roleNames() const
void PlasmoidModel::addApplet(Plasma::Applet *applet)
{
auto pluginMetaData = applet->pluginMetaData();
QStandardItem *dataItem = nullptr;
for (int i = 0; i < rowCount(); i++) {
QStandardItem *currentItem = item(i);
if (currentItem->data(static_cast<int>(BaseModel::BaseRole::ItemId)) == pluginMetaData.pluginId()) {
dataItem = currentItem;
break;
}
}
if (!dataItem) {
QString name = pluginMetaData.name();
const QString dbusactivation = pluginMetaData.value(QStringLiteral("X-Plasma-DBusActivationService"));
if (!dbusactivation.isEmpty()) {
name += i18n(" (Automatic load)");
}
dataItem = new QStandardItem(QIcon::fromTheme(pluginMetaData.iconName()), name);
appendRow(dataItem);
int idx = indexOfPluginId(pluginMetaData.pluginId());
if (idx < 0) {
idx = rowCount();
appendRow(pluginMetaData);
}
dataItem->setData(pluginMetaData.pluginId(), static_cast<int>(BaseModel::BaseRole::ItemId));
dataItem->setData(plasmoidCategoryForMetadata(pluginMetaData), static_cast<int>(BaseModel::BaseRole::Category));
dataItem->setData(applet->status(), static_cast<int>(BaseModel::BaseRole::Status));
connect(applet, &Plasma::Applet::statusChanged, this, [dataItem] (Plasma::Types::ItemStatus status) {
dataItem->setData(status, static_cast<int>(BaseModel::BaseRole::Status));
m_items[idx].applet = applet;
connect(applet, &Plasma::Applet::statusChanged, this, [this, applet] (Plasma::Types::ItemStatus status) {
Q_UNUSED(status)
int idx = indexOfPluginId(applet->pluginMetaData().pluginId());
dataChanged(index(idx, 0), index(idx, 0), {static_cast<int>(BaseRole::Status)});
});
dataItem->setData(applet->property("_plasma_graphicObject"), static_cast<int>(Role::Applet));
dataItem->setData(true, static_cast<int>(Role::HasApplet));
// CanRender has to be the last one
dataItem->setData(true, static_cast<int>(BaseModel::BaseRole::CanRender));
dataChanged(index(idx, 0), index(idx, 0));
}
void PlasmoidModel::removeApplet(Plasma::Applet *applet)
{
int rows = rowCount();
for (int i = 0; i < rows; i++) {
QStandardItem *currentItem = item(i);
QVariant plugin = currentItem->data(static_cast<int>(BaseModel::BaseRole::ItemId));
if (plugin.isValid() && plugin.value<QString>() == applet->pluginMetaData().pluginId()) {
currentItem->setData(false, static_cast<int>(BaseModel::BaseRole::CanRender));
currentItem->setData(QVariant(), static_cast<int>(Role::Applet));
currentItem->setData(false, static_cast<int>(Role::HasApplet));
applet->disconnect(this);
return;
int idx = indexOfPluginId(applet->pluginMetaData().pluginId());
if (idx > 0) {
applet->disconnect(this);
m_items[idx].applet = nullptr;
dataChanged(index(idx, 0), index(idx, 0));
}
}
void PlasmoidModel::appendRow(const KPluginMetaData &pluginMetaData)
{
int idx = rowCount();
beginInsertRows(QModelIndex(), idx, idx);
PlasmoidModel::Item item;
item.pluginMetaData = pluginMetaData;
m_items.append(item);
endInsertRows();
}
int PlasmoidModel::indexOfPluginId(const QString &pluginId) const {
for (int i = 0; i < rowCount(); i++) {