Commit 6d86c690 authored by Konrad Materka's avatar Konrad Materka

[applets/SystemTray] Implement sorting in the model

Summary:
Replace two wrapping PlasmaCore.SortFilterModel with custom sorting on model side. Extract common code to base class.
This fixes small issue in sorting and allows to implement other improvements (later on).

Test Plan: Everything should work as before.

Reviewers: #plasma_workspaces, #plasma, davidedmundson, ngraham, broulik

Reviewed By: #plasma_workspaces, #plasma, davidedmundson, ngraham

Subscribers: mart, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D27088
parent 8c380a8e
......@@ -4,6 +4,7 @@ plasma_install_package(package org.kde.plasma.private.systemtray)
set(systemtray_SRCS
systemtraymodel.cpp
sortedsystemtraymodel.cpp
systemtray.cpp
)
......
......@@ -75,19 +75,7 @@ ColumnLayout {
property var visibilityColumnWidth: units.gridUnit
property var keySequenceColumnWidth: units.gridUnit
model: PlasmaCore.SortFilterModel {
sourceModel: PlasmaCore.SortFilterModel {
sourceModel: plasmoid.nativeInterface.systemTrayModel
sortRole: "display"
sortColumn: 0
isSortLocaleAware: true
}
sortRole: "category"
sortColumn: 0
isSortLocaleAware: true
}
model: plasmoid.nativeInterface.configSystemTrayModel
header: Kirigami.AbstractListItem {
......
/***************************************************************************
* Copyright (C) 2019 Konrad Materka <materka@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#include "sortedsystemtraymodel.h"
#include "systemtraymodel.h"
#include "debug.h"
#include <QList>
SortedSystemTrayModel::SortedSystemTrayModel(SortingType sorting, QObject *parent)
: QSortFilterProxyModel(parent),
m_sorting(sorting)
{
setSortLocaleAware(true);
sort(0);
}
bool SortedSystemTrayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
switch (m_sorting) {
case SortedSystemTrayModel::SortingType::ConfigurationPage:
return lessThanConfigurationPage(left, right);
}
return QSortFilterProxyModel::lessThan(left, right);
}
bool SortedSystemTrayModel::lessThanConfigurationPage(const QModelIndex &left, const QModelIndex &right) const
{
const int categoriesComparison = compareCategoriesAlphabetically(left, right);
if (categoriesComparison == 0) {
return QSortFilterProxyModel::lessThan(left, right);
} else {
return categoriesComparison < 0;
}
}
int SortedSystemTrayModel::compareCategoriesAlphabetically(const QModelIndex &left, const QModelIndex &right) const
{
QVariant leftData = sourceModel()->data(left, static_cast<int>(BaseModel::BaseRole::Category));
QString leftCategory = leftData.isNull() ? QStringLiteral("UnknownCategory") : leftData.toString();
QVariant rightData = sourceModel()->data(right, static_cast<int>(BaseModel::BaseRole::Category));
QString rightCategory = rightData.isNull() ? QStringLiteral("UnknownCategory") : rightData.toString();
return QString::localeAwareCompare(leftCategory, rightCategory);
}
/***************************************************************************
* Copyright (C) 2019 Konrad Materka <materka@gmail.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
***************************************************************************/
#ifndef SORTEDSYSTEMTRAYMODEL_H
#define SORTEDSYSTEMTRAYMODEL_H
#include <QSortFilterProxyModel>
class SortedSystemTrayModel : public QSortFilterProxyModel {
Q_OBJECT
public:
enum class SortingType {
ConfigurationPage
};
explicit SortedSystemTrayModel(SortingType sorting, QObject *parent = nullptr);
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
private:
bool lessThanConfigurationPage(const QModelIndex &left, const QModelIndex &right) const;
int compareCategoriesAlphabetically(const QModelIndex &left, const QModelIndex &right) const;
SortingType m_sorting;
};
#endif // SORTEDSYSTEMTRAYMODEL_H
......@@ -19,6 +19,7 @@
#include "systemtray.h"
#include "systemtraymodel.h"
#include "sortedsystemtraymodel.h"
#include "debug.h"
#include <QDBusConnection>
......@@ -43,7 +44,8 @@
SystemTray::SystemTray(QObject *parent, const QVariantList &args)
: Plasma::Containment(parent, args),
m_availablePlasmoidsModel(nullptr),
m_systemTrayModel(new SystemTrayModel(this))
m_systemTrayModel(new SystemTrayModel(this)),
m_configSystemTrayModel(nullptr)
{
setHasConfigurationInterface(true);
setContainmentType(Plasma::Types::CustomEmbeddedContainment);
......@@ -51,9 +53,10 @@ SystemTray::SystemTray(QObject *parent, const QVariantList &args)
PlasmoidModel *currentPlasmoidsModel = new PlasmoidModel(m_systemTrayModel);
connect(this, &SystemTray::appletAdded, currentPlasmoidsModel, &PlasmoidModel::addApplet);
connect(this, &SystemTray::appletRemoved, currentPlasmoidsModel, &PlasmoidModel::removeApplet);
m_systemTrayModel->addSourceModel(currentPlasmoidsModel);
m_statusNotifierModel = new StatusNotifierModel(m_systemTrayModel);
m_systemTrayModel->addSourceModel(currentPlasmoidsModel);
m_systemTrayModel->addSourceModel(m_statusNotifierModel);
}
......@@ -386,8 +389,6 @@ void SystemTray::restorePlasmoids()
}
}
QStringList ownApplets;
QMap<QString, KPluginMetaData> sortedApplets;
for (auto it = m_systrayApplets.constBegin(); it != m_systrayApplets.constEnd(); ++it) {
const KPluginMetaData &info = it.value();
......@@ -429,9 +430,13 @@ void SystemTray::restorePlasmoids()
initDBusActivatables();
}
QAbstractItemModel *SystemTray::systemTrayModel()
QAbstractItemModel *SystemTray::configSystemTrayModel()
{
return m_systemTrayModel;
if (!m_configSystemTrayModel) {
m_configSystemTrayModel = new SortedSystemTrayModel(SortedSystemTrayModel::SortingType::ConfigurationPage, this);
m_configSystemTrayModel->setSourceModel(m_systemTrayModel);
}
return m_configSystemTrayModel;
}
QStringList SystemTray::defaultPlasmoids() const
......@@ -487,7 +492,7 @@ void SystemTray::initDBusActivatables()
connect(systemCallWatcher, &QDBusPendingCallWatcher::finished,
[=](QDBusPendingCallWatcher *callWatcher){
SystemTray::serviceNameFetchFinished(callWatcher, QDBusConnection::systemBus());
});
});
}
void SystemTray::serviceNameFetchFinished(QDBusPendingCallWatcher* watcher, const QDBusConnection &connection)
......
......@@ -35,11 +35,12 @@ namespace Plasma {
class PlasmoidModel;
class StatusNotifierModel;
class SystemTrayModel;
class SortedSystemTrayModel;
class SystemTray : public Plasma::Containment
{
Q_OBJECT
Q_PROPERTY(QAbstractItemModel* systemTrayModel READ systemTrayModel CONSTANT)
Q_PROPERTY(QAbstractItemModel* configSystemTrayModel READ configSystemTrayModel CONSTANT)
Q_PROPERTY(QAbstractItemModel* availablePlasmoids READ availablePlasmoids CONSTANT)
Q_PROPERTY(QStringList allowedPlasmoids READ allowedPlasmoids WRITE setAllowedPlasmoids NOTIFY allowedPlasmoidsChanged)
Q_PROPERTY(QStringList defaultPlasmoids READ defaultPlasmoids CONSTANT)
......@@ -53,7 +54,7 @@ public:
void restoreContents(KConfigGroup &group) override;
void restorePlasmoids();
QAbstractItemModel* systemTrayModel();
QAbstractItemModel *configSystemTrayModel();
QStringList defaultPlasmoids() const;
......@@ -130,6 +131,7 @@ private:
PlasmoidModel *m_availablePlasmoidsModel;
StatusNotifierModel *m_statusNotifierModel;
SystemTrayModel *m_systemTrayModel;
SortedSystemTrayModel *m_configSystemTrayModel;
QHash<QString, int> m_knownPlugins;
QHash<QString, int> m_dbusServiceCounts;
};
......
......@@ -29,6 +29,23 @@
#include <KLocalizedString>
BaseModel::BaseModel(QObject *parent)
: QStandardItemModel(parent)
{
}
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"));
return roles;
}
static QString plasmoidCategoryForMetadata(const KPluginMetaData &metadata)
{
QString category = QStringLiteral("UnknownCategory");
......@@ -43,7 +60,7 @@ static QString plasmoidCategoryForMetadata(const KPluginMetaData &metadata)
return category;
}
PlasmoidModel::PlasmoidModel(QObject *parent) : QStandardItemModel(parent)
PlasmoidModel::PlasmoidModel(QObject *parent) : BaseModel(parent)
{
for (const auto &info : Plasma::PluginLoader::self()->listAppletMetaData(QString())) {
if (!info.isValid() || info.value(QStringLiteral("X-Plasma-NotificationArea")) != "true") {
......@@ -58,24 +75,18 @@ PlasmoidModel::PlasmoidModel(QObject *parent) : QStandardItemModel(parent)
name += i18n(" (Automatic load)");
}
QStandardItem *item = new QStandardItem(QIcon::fromTheme(info.iconName()), name);
item->setData(info.pluginId(), static_cast<int>(BaseRole::ItemId));
item->setData(QStringLiteral("Plasmoid"), static_cast<int>(BaseRole::ItemType));
item->setData(false, static_cast<int>(BaseRole::CanRender));
item->setData(plasmoidCategoryForMetadata(info), static_cast<int>(BaseRole::Category));
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);
}
sort(0);
}
QHash<int, QByteArray> PlasmoidModel::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"));
QHash<int, QByteArray> roles = BaseModel::roleNames();
roles.insert(static_cast<int>(Role::Applet), QByteArrayLiteral("applet"));
roles.insert(static_cast<int>(Role::HasApplet), QByteArrayLiteral("hasApplet"));
......@@ -85,26 +96,36 @@ QHash<int, QByteArray> PlasmoidModel::roleNames() const
void PlasmoidModel::addApplet(Plasma::Applet *applet)
{
auto info = applet->pluginMetaData();
auto pluginMetaData = applet->pluginMetaData();
QStandardItem *dataItem = nullptr;
for (int i = 0; i < rowCount(); i++) {
QStandardItem *currentItem = item(i);
if (currentItem->data(static_cast<int>(BaseRole::ItemId)) == info.pluginId()) {
if (currentItem->data(static_cast<int>(BaseModel::BaseRole::ItemId)) == pluginMetaData.pluginId()) {
dataItem = currentItem;
break;
}
}
if (!dataItem) {
dataItem = new QStandardItem(QIcon::fromTheme(info.iconName()), info.name());
dataItem = new QStandardItem();
appendRow(dataItem);
}
dataItem->setData(info.pluginId(), static_cast<int>(BaseRole::ItemId));
dataItem->setData(applet->title(), Qt::DisplayRole);
connect(applet, &Plasma::Applet::titleChanged, this, [dataItem] (const QString &title) {
dataItem->setData(title, static_cast<int>(Qt::DisplayRole));
});
dataItem->setData(QIcon::fromTheme(applet->icon()), Qt::DecorationRole);
connect(applet, &Plasma::Applet::iconChanged, this, [dataItem] (const QString &icon) {
dataItem->setData(QIcon::fromTheme(icon), Qt::DecorationRole);
});
dataItem->setData(pluginMetaData.pluginId(), static_cast<int>(BaseModel::BaseRole::ItemId));
dataItem->setData(true, static_cast<int>(BaseModel::BaseRole::CanRender));
dataItem->setData(plasmoidCategoryForMetadata(pluginMetaData), static_cast<int>(BaseModel::BaseRole::Category));
dataItem->setData(applet->property("_plasma_graphicObject"), static_cast<int>(Role::Applet));
dataItem->setData(true, static_cast<int>(Role::HasApplet));
dataItem->setData(true, static_cast<int>(BaseRole::CanRender));
dataItem->setData(plasmoidCategoryForMetadata(applet->pluginMetaData()), static_cast<int>(BaseRole::Category));
}
void PlasmoidModel::removeApplet(Plasma::Applet *applet)
......@@ -112,17 +133,18 @@ 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>(BaseRole::ItemId));
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>(BaseRole::CanRender));
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;
}
}
}
StatusNotifierModel::StatusNotifierModel(QObject *parent) : QStandardItemModel(parent)
StatusNotifierModel::StatusNotifierModel(QObject *parent) : BaseModel(parent)
{
m_dataEngine = dataEngine(QStringLiteral("statusnotifieritem"));
......@@ -134,12 +156,7 @@ StatusNotifierModel::StatusNotifierModel(QObject *parent) : QStandardItemModel(p
QHash<int, QByteArray> StatusNotifierModel::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"));
QHash<int, QByteArray> roles = BaseModel::roleNames();
roles.insert(static_cast<int>(Role::DataEngineSource), QByteArrayLiteral("DataEngineSource"));
roles.insert(static_cast<int>(Role::AttentionIcon), QByteArrayLiteral("AttentionIcon"));
......@@ -207,8 +224,8 @@ void StatusNotifierModel::dataUpdated(const QString &sourceName, const Plasma::D
dataItem = item(m_sources.indexOf(sourceName));
} else {
dataItem = new QStandardItem();
dataItem->setData(QStringLiteral("StatusNotifier"), static_cast<int>(BaseRole::ItemType));
dataItem->setData(true, static_cast<int>(BaseRole::CanRender));
dataItem->setData(QStringLiteral("StatusNotifier"), static_cast<int>(BaseModel::BaseRole::ItemType));
dataItem->setData(true, static_cast<int>(BaseModel::BaseRole::CanRender));
}
dataItem->setData(data.value("Title"), Qt::DisplayRole);
......@@ -219,8 +236,9 @@ void StatusNotifierModel::dataUpdated(const QString &sourceName, const Plasma::D
dataItem->setData(data.value("IconName"), Qt::DecorationRole);
}
dataItem->setData(data.value("Id"), static_cast<int>(BaseRole::ItemId));
dataItem->setData(data.value("Category"), static_cast<int>(BaseRole::Category));
dataItem->setData(data.value("Id"), static_cast<int>(BaseModel::BaseRole::ItemId));
QVariant category = data.value("Category");
dataItem->setData(category.isNull() ? QStringLiteral("UnknownCategory") : data.value("Category"), static_cast<int>(BaseModel::BaseRole::Category));
dataItem->setData(sourceName, static_cast<int>(Role::DataEngineSource));
updateItemData(dataItem, data, Role::AttentionIcon);
......
......@@ -30,20 +30,29 @@ namespace Plasma {
class Applet;
}
enum class BaseRole {
ItemType = Qt::UserRole + 1,
ItemId,
CanRender,
Category,
LastBaseRole
class BaseModel: public QStandardItemModel
{
Q_OBJECT
public:
enum class BaseRole {
ItemType = Qt::UserRole + 1,
ItemId,
CanRender,
Category,
LastBaseRole
};
explicit BaseModel(QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
};
class PlasmoidModel: public QStandardItemModel
class PlasmoidModel: public BaseModel
{
Q_OBJECT
public:
enum class Role {
Applet = static_cast<int>(BaseRole::LastBaseRole) + 1,
Applet = static_cast<int>(BaseModel::BaseRole::LastBaseRole) + 1,
HasApplet
};
......@@ -56,11 +65,11 @@ public slots:
void removeApplet(Plasma::Applet *applet);
};
class StatusNotifierModel : public QStandardItemModel, public Plasma::DataEngineConsumer {
class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer {
Q_OBJECT
public:
enum class Role {
DataEngineSource = static_cast<int>(BaseRole::LastBaseRole) + 100,
DataEngineSource = static_cast<int>(BaseModel::BaseRole::LastBaseRole) + 100,
AttentionIcon,
AttentionIconName,
AttentionMovieName,
......
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