diff --git a/applets/systemtray/package/contents/applet/CompactApplet.qml b/applets/systemtray/package/contents/applet/CompactApplet.qml index 6975639cd..e8052bad0 100644 --- a/applets/systemtray/package/contents/applet/CompactApplet.qml +++ b/applets/systemtray/package/contents/applet/CompactApplet.qml @@ -1,82 +1,81 @@ /* * Copyright 2011 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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. */ import QtQuick 2.1 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.plasmoid 2.0 PlasmaCore.ToolTipArea { id: appletRoot objectName: "org.kde.desktop-CompactApplet" anchors.fill: parent - icon: plasmoid.icon mainText: plasmoid.toolTipMainText subText: plasmoid.toolTipSubText location: if (plasmoid.parent && plasmoid.parent.inHiddenLayout && plasmoid.location !== PlasmaCore.Types.LeftEdge) { return PlasmaCore.Types.RightEdge; } else { return plasmoid.location; } active: !plasmoid.expanded textFormat: plasmoid.toolTipTextFormat mainItem: plasmoid.toolTipItem ? plasmoid.toolTipItem : null property Item fullRepresentation property Item compactRepresentation Connections { target: plasmoid onContextualActionsAboutToShow: appletRoot.hideToolTip() } Layout.minimumWidth: { switch (plasmoid.formFactor) { case PlasmaCore.Types.Vertical: return 0; case PlasmaCore.Types.Horizontal: return height; default: return units.gridUnit * 3; } } Layout.minimumHeight: { switch (plasmoid.formFactor) { case PlasmaCore.Types.Vertical: return width; case PlasmaCore.Types.Horizontal: return 0; default: return units.gridUnit * 3; } } onCompactRepresentationChanged: { if (compactRepresentation) { compactRepresentation.parent = appletRoot; compactRepresentation.anchors.fill = appletRoot; compactRepresentation.visible = true; } appletRoot.visible = true; } } diff --git a/applets/systemtray/package/contents/ui/items/AbstractItem.qml b/applets/systemtray/package/contents/ui/items/AbstractItem.qml index 8f7531930..a2f323e2e 100644 --- a/applets/systemtray/package/contents/ui/items/AbstractItem.qml +++ b/applets/systemtray/package/contents/ui/items/AbstractItem.qml @@ -1,152 +1,151 @@ /* * Copyright 2016 Marco Martin * Copyright 2020 Konrad Materka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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. */ import QtQuick 2.2 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents PlasmaCore.ToolTipArea { id: abstractItem height: inVisibleLayout ? visibleLayout.cellHeight : hiddenLayout.iconItemHeight width: inVisibleLayout ? visibleLayout.cellWidth : hiddenLayout.width property var model: itemModel property string itemId property alias text: label.text property alias iconContainer: iconContainer property int /*PlasmaCore.Types.ItemStatus*/ status: model.status || PlasmaCore.Types.UnknownStatus property int /*PlasmaCore.Types.ItemStatus*/ effectiveStatus: model.effectiveStatus || PlasmaCore.Types.UnknownStatus readonly property bool inHiddenLayout: effectiveStatus === PlasmaCore.Types.PassiveStatus readonly property bool inVisibleLayout: effectiveStatus === PlasmaCore.Types.ActiveStatus signal clicked(var mouse) signal pressed(var mouse) signal wheel(var wheel) signal contextMenu(var mouse) /* subclasses need to assign to this tooltip properties mainText: subText: - icon: */ location: { if (inHiddenLayout) { if (LayoutMirroring.enabled && plasmoid.location !== PlasmaCore.Types.RightEdge) { return PlasmaCore.Types.LeftEdge; } else if (plasmoid.location !== PlasmaCore.Types.LeftEdge) { return PlasmaCore.Types.RightEdge; } } return plasmoid.location; } //BEGIN CONNECTIONS onContainsMouseChanged: { if (inHiddenLayout && containsMouse) { root.hiddenLayout.currentIndex = index } } //END CONNECTIONS PulseAnimation { targetItem: iconContainer running: (abstractItem.status === PlasmaCore.Types.NeedsAttentionStatus || abstractItem.status === PlasmaCore.Types.RequiresAttentionStatus ) && units.longDuration > 0 } function activated() { activatedAnimation.start() } SequentialAnimation { id: activatedAnimation loops: 1 ScaleAnimator { target: iconContainer from: 1 to: 0.5 duration: units.shortDuration easing.type: Easing.InQuad } ScaleAnimator { target: iconContainer from: 0.5 to: 1 duration: units.shortDuration easing.type: Easing.OutQuad } } MouseArea { anchors.fill: abstractItem hoverEnabled: true drag.filterChildren: true acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton onClicked: abstractItem.clicked(mouse) onPressed: { abstractItem.hideToolTip() abstractItem.pressed(mouse) } onPressAndHold: { abstractItem.contextMenu(mouse) } onWheel: { abstractItem.wheel(wheel); //Don't accept the event in order to make the scrolling by mouse wheel working //for the parent scrollview this icon is in. wheel.accepted = false; } } Row { spacing: units.smallSpacing anchors.horizontalCenter: inVisibleLayout ? parent.horizontalCenter : undefined Item { id: iconContainer anchors.verticalCenter: parent.verticalCenter width: Math.min(abstractItem.width, abstractItem.height) height: width property alias inHiddenLayout: abstractItem.inHiddenLayout property alias inVisibleLayout: abstractItem.inVisibleLayout } PlasmaComponents.Label { id: label anchors.verticalCenter: parent.verticalCenter visible: abstractItem.inHiddenLayout && !root.activeApplet opacity: visible ? 1 : 0 Behavior on opacity { NumberAnimation { duration: units.longDuration easing.type: Easing.InOutQuad } } } } } diff --git a/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml b/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml index ae8e76ddb..bdfee82d8 100644 --- a/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml +++ b/applets/systemtray/package/contents/ui/items/PlasmoidItem.qml @@ -1,106 +1,105 @@ /* * Copyright 2015 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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. */ import QtQuick 2.1 import org.kde.plasma.core 2.0 as PlasmaCore AbstractItem { id: plasmoidContainer property Item applet: model.applet || null text: applet ? applet.title : "" itemId: applet ? applet.pluginName : "" mainText: applet ? applet.toolTipMainText : "" subText: applet ? applet.toolTipSubText : "" - icon: applet ? applet.icon : "" mainItem: applet && applet.toolTipItem ? applet.toolTipItem : null textFormat: applet ? applet.toolTipTextFormat : "" active: root.activeApplet !== applet onClicked: { if (applet && mouse.button === Qt.LeftButton) { applet.expanded = true; } } onPressed: { if (mouse.button === Qt.RightButton) { plasmoidContainer.contextMenu(mouse); } } onContextMenu: { if (applet) { plasmoid.nativeInterface.showPlasmoidMenu(applet, 0, plasmoidContainer.inHiddenLayout ? applet.height : 0); } } //This is to make preloading effective, minimizes the scene changes function preloadFullRepresentationItem(fullRepresentationItem) { if (fullRepresentationItem && fullRepresentationItem.parent === null) { fullRepresentationItem.width = expandedRepresentation.width fullRepresentationItem.width = expandedRepresentation.height fullRepresentationItem.parent = preloadedStorage; } } onAppletChanged: { if (applet) { applet.parent = plasmoidContainer.iconContainer applet.anchors.fill = applet.parent applet.visible = true preloadFullRepresentationItem(applet.fullRepresentationItem) } } Connections { target: applet onActivated: plasmoidContainer.activated() onExpandedChanged: { if (expanded) { var oldApplet = root.activeApplet; root.activeApplet = applet; if (oldApplet && oldApplet !== applet) { oldApplet.expanded = false; } dialog.visible = true; plasmoidContainer.activated() } else if (root.activeApplet === applet) { if (!inHiddenLayout) { dialog.visible = false; } //if not expanded we don't have an active applet anymore root.activeApplet = null; } } onFullRepresentationItemChanged: { preloadFullRepresentationItem(fullRepresentationItem) } } Binding { property: "hideOnWindowDeactivate" value: !plasmoid.configuration.pin target: plasmoidContainer.applet when: null !== plasmoidContainer.applet } } diff --git a/applets/systemtray/package/contents/ui/items/StatusNotifierItem.qml b/applets/systemtray/package/contents/ui/items/StatusNotifierItem.qml index db9fa7613..4db0c611b 100644 --- a/applets/systemtray/package/contents/ui/items/StatusNotifierItem.qml +++ b/applets/systemtray/package/contents/ui/items/StatusNotifierItem.qml @@ -1,120 +1,119 @@ /* * Copyright 2016 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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. */ import QtQuick 2.1 import org.kde.plasma.core 2.0 as PlasmaCore AbstractItem { id: taskIcon itemId: model.Id text: model.Title mainText: model.ToolTipTitle !== "" ? model.ToolTipTitle : model.Title subText: model.ToolTipSubTitle - icon: model.ToolTipIcon !== "" ? model.ToolTipIcon : model.Icon ? model.Icon : model.IconName textFormat: Text.AutoText PlasmaCore.IconItem { id: iconItem parent: taskIcon.iconContainer anchors.fill: iconItem.parent source: { if (model.status === PlasmaCore.Types.NeedsAttentionStatus) { if (model.AttentionIcon) { return model.AttentionIcon } if (model.AttentionIconName) { return model.AttentionIconName } } return model.Icon ? model.Icon : model.IconName } active: taskIcon.containsMouse } onContextMenu: { openContextMenu(plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y)) } onClicked: { var pos = plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y); 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; var job = service.startOperationCall(operation); job.finished.connect(function () { if (!job.result) { // On error try to invoke the context menu. // Workaround primarily for apps using libappindicator. openContextMenu(pos); } }); taskIcon.activated() break; case Qt.RightButton: openContextMenu(pos); break; case Qt.MiddleButton: var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource); var operation = service.operationDescription("SecondaryActivate"); operation.x = pos.x; operation.y = pos.y; service.startOperationCall(operation); taskIcon.activated() break; } } function openContextMenu(pos) { var service = plasmoid.nativeInterface.serviceForSource(model.DataEngineSource); var operation = service.operationDescription("ContextMenu"); operation.x = pos.x; operation.y = pos.y; var job = service.startOperationCall(operation); job.finished.connect(function () { plasmoid.nativeInterface.showStatusNotifierContextMenu(job, taskIcon); }); } 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 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 operation = service.operationDescription("Scroll"); operation.delta =wheel.angleDelta.x; operation.direction = "Horizontal"; service.startOperationCall(operation); } } } diff --git a/applets/systemtray/systemtraymodel.cpp b/applets/systemtray/systemtraymodel.cpp index 95e87f108..a4ff771d3 100644 --- a/applets/systemtray/systemtraymodel.cpp +++ b/applets/systemtray/systemtraymodel.cpp @@ -1,398 +1,396 @@ /*************************************************************************** * Copyright (C) 2019 Konrad Materka * * * * 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 "systemtraymodel.h" #include "debug.h" #include #include #include #include #include #include BaseModel::BaseModel(QObject *parent) : QStandardItemModel(parent), m_showAllItems(false) { connect(this, &BaseModel::rowsInserted, this, &BaseModel::onRowsInserted); connect(this, &BaseModel::dataChanged, this, &BaseModel::onDataChanged); } QHash BaseModel::roleNames() const { QHash roles = QStandardItemModel::roleNames(); roles.insert(static_cast(BaseRole::ItemType), QByteArrayLiteral("itemType")); roles.insert(static_cast(BaseRole::ItemId), QByteArrayLiteral("itemId")); roles.insert(static_cast(BaseRole::CanRender), QByteArrayLiteral("canRender")); roles.insert(static_cast(BaseRole::Category), QByteArrayLiteral("category")); roles.insert(static_cast(BaseRole::Status), QByteArrayLiteral("status")); roles.insert(static_cast(BaseRole::EffectiveStatus), QByteArrayLiteral("effectiveStatus")); return roles; } void BaseModel::onConfigurationChanged(const KConfigGroup &config) { if (!config.isValid()) { return; } const KConfigGroup generalGroup = config.group("General"); m_showAllItems = generalGroup.readEntry("showAllItems", false); m_shownItems = generalGroup.readEntry("shownItems", QStringList()); 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 &roles) { if (roles.contains(static_cast(BaseRole::Status)) || roles.contains(static_cast(BaseRole::CanRender))) { for (int i = topLeft.row(); i <= bottomRight.row(); i++) { QStandardItem *dataItem = item(i); updateEffectiveStatus(dataItem); } } } void BaseModel::updateEffectiveStatus(QStandardItem *dataItem) { Plasma::Types::ItemStatus status = calculateEffectiveStatus(dataItem); dataItem->setData(status, static_cast(BaseModel::BaseRole::EffectiveStatus)); } Plasma::Types::ItemStatus BaseModel::calculateEffectiveStatus(QStandardItem *dataItem) { bool canRender = dataItem->data(static_cast(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(BaseRole::ItemId)).toString(); bool forcedShown = m_showAllItems || m_shownItems.contains(itemId); bool forcedHidden = m_hiddenItems.contains(itemId); if (forcedShown || (!forcedHidden && status != Plasma::Types::ItemStatus::PassiveStatus)) { return Plasma::Types::ItemStatus::ActiveStatus; } else { return Plasma::Types::ItemStatus::PassiveStatus; } } Plasma::Types::ItemStatus BaseModel::readStatus(QStandardItem *dataItem) const { QVariant statusData = dataItem->data(static_cast(BaseRole::Status)); if (statusData.isValid()) { return statusData.value(); } else { return Plasma::Types::ItemStatus::UnknownStatus; } } static QString plasmoidCategoryForMetadata(const KPluginMetaData &metadata) { QString category = QStringLiteral("UnknownCategory"); if (metadata.isValid()) { const QString notificationAreaCategory = metadata.value(QStringLiteral("X-Plasma-NotificationAreaCategory")); if (!notificationAreaCategory.isEmpty()) { category = notificationAreaCategory; } } return category; } 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") { continue; } QString name = info.name(); const QString dbusactivation = info.rawData().value(QStringLiteral("X-Plasma-DBusActivationService")).toString(); if (!dbusactivation.isEmpty()) { name += i18n(" (Automatic load)"); } QStandardItem *item = new QStandardItem(QIcon::fromTheme(info.iconName()), name); item->setData(info.pluginId(), static_cast(BaseModel::BaseRole::ItemId)); item->setData(QStringLiteral("Plasmoid"), static_cast(BaseModel::BaseRole::ItemType)); item->setData(false, static_cast(BaseModel::BaseRole::CanRender)); item->setData(plasmoidCategoryForMetadata(info), static_cast(BaseModel::BaseRole::Category)); item->setData(false, static_cast(Role::HasApplet)); appendRow(item); } } QHash PlasmoidModel::roleNames() const { QHash roles = BaseModel::roleNames(); roles.insert(static_cast(Role::Applet), QByteArrayLiteral("applet")); roles.insert(static_cast(Role::HasApplet), QByteArrayLiteral("hasApplet")); return roles; } 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(BaseModel::BaseRole::ItemId)) == pluginMetaData.pluginId()) { dataItem = currentItem; break; } } if (!dataItem) { dataItem = new QStandardItem(); appendRow(dataItem); } dataItem->setData(applet->title(), Qt::DisplayRole); connect(applet, &Plasma::Applet::titleChanged, this, [dataItem] (const QString &title) { dataItem->setData(title, static_cast(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(BaseModel::BaseRole::ItemId)); dataItem->setData(true, static_cast(BaseModel::BaseRole::CanRender)); dataItem->setData(plasmoidCategoryForMetadata(pluginMetaData), static_cast(BaseModel::BaseRole::Category)); dataItem->setData(applet->status(), static_cast(BaseModel::BaseRole::Status)); connect(applet, &Plasma::Applet::statusChanged, this, [dataItem] (Plasma::Types::ItemStatus status) { dataItem->setData(status, static_cast(BaseModel::BaseRole::Status)); }); dataItem->setData(applet->property("_plasma_graphicObject"), static_cast(Role::Applet)); dataItem->setData(true, static_cast(Role::HasApplet)); } 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(BaseModel::BaseRole::ItemId)); if (plugin.isValid() && plugin.value() == applet->pluginMetaData().pluginId()) { currentItem->setData(false, static_cast(BaseModel::BaseRole::CanRender)); currentItem->setData(QVariant(), static_cast(Role::Applet)); currentItem->setData(false, static_cast(Role::HasApplet)); applet->disconnect(this); return; } } } StatusNotifierModel::StatusNotifierModel(QObject *parent) : BaseModel(parent) { m_dataEngine = dataEngine(QStringLiteral("statusnotifieritem")); connect(m_dataEngine, &Plasma::DataEngine::sourceAdded, this, &StatusNotifierModel::addSource); connect(m_dataEngine, &Plasma::DataEngine::sourceRemoved, this, &StatusNotifierModel::removeSource); m_dataEngine->connectAllSources(this); } QHash StatusNotifierModel::roleNames() const { QHash roles = BaseModel::roleNames(); roles.insert(static_cast(Role::DataEngineSource), QByteArrayLiteral("DataEngineSource")); roles.insert(static_cast(Role::AttentionIcon), QByteArrayLiteral("AttentionIcon")); roles.insert(static_cast(Role::AttentionIconName), QByteArrayLiteral("AttentionIconName")); roles.insert(static_cast(Role::AttentionMovieName), QByteArrayLiteral("AttentionMovieName")); roles.insert(static_cast(Role::Category), QByteArrayLiteral("Category")); roles.insert(static_cast(Role::Icon), QByteArrayLiteral("Icon")); roles.insert(static_cast(Role::IconName), QByteArrayLiteral("IconName")); roles.insert(static_cast(Role::IconThemePath), QByteArrayLiteral("IconThemePath")); roles.insert(static_cast(Role::IconsChanged), QByteArrayLiteral("IconsChanged")); roles.insert(static_cast(Role::Id), QByteArrayLiteral("Id")); roles.insert(static_cast(Role::ItemIsMenu), QByteArrayLiteral("ItemIsMenu")); roles.insert(static_cast(Role::OverlayIconName), QByteArrayLiteral("OverlayIconName")); roles.insert(static_cast(Role::Status), QByteArrayLiteral("Status")); roles.insert(static_cast(Role::StatusChanged), QByteArrayLiteral("StatusChanged")); roles.insert(static_cast(Role::Title), QByteArrayLiteral("Title")); roles.insert(static_cast(Role::TitleChanged), QByteArrayLiteral("TitleChanged")); roles.insert(static_cast(Role::ToolTipChanged), QByteArrayLiteral("ToolTipChanged")); - roles.insert(static_cast(Role::ToolTipIcon), QByteArrayLiteral("ToolTipIcon")); roles.insert(static_cast(Role::ToolTipSubTitle), QByteArrayLiteral("ToolTipSubTitle")); roles.insert(static_cast(Role::ToolTipTitle), QByteArrayLiteral("ToolTipTitle")); roles.insert(static_cast(Role::WindowId), QByteArrayLiteral("WindowId")); return roles; } Plasma::Service *StatusNotifierModel::serviceForSource(const QString &source) { if (m_services.contains(source)) { return m_services.value(source); } Plasma::Service *service = m_dataEngine->serviceForSource(source); if (!service) { return nullptr; } m_services[source] = service; return service; } void StatusNotifierModel::addSource(const QString &source) { m_dataEngine->connectSource(source, this); } void StatusNotifierModel::removeSource(const QString &source) { m_dataEngine->disconnectSource(source, this); if (m_sources.contains(source)) { removeRow(m_sources.indexOf(source)); m_sources.removeAll(source); } QHash::iterator it = m_services.find(source); if (it != m_services.end()) { delete it.value(); m_services.erase(it); } } void StatusNotifierModel::dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data) { QStandardItem *dataItem; if (m_sources.contains(sourceName)) { dataItem = item(m_sources.indexOf(sourceName)); } else { dataItem = new QStandardItem(); dataItem->setData(QStringLiteral("StatusNotifier"), static_cast(BaseModel::BaseRole::ItemType)); dataItem->setData(true, static_cast(BaseModel::BaseRole::CanRender)); } dataItem->setData(data.value("Title"), Qt::DisplayRole); QVariant icon = data.value("Icon"); if (icon.isValid() && icon.canConvert() && !icon.value().isNull()) { dataItem->setData(icon, Qt::DecorationRole); } else { dataItem->setData(data.value("IconName"), Qt::DecorationRole); } dataItem->setData(data.value("Id"), static_cast(BaseModel::BaseRole::ItemId)); QVariant category = data.value("Category"); dataItem->setData(category.isNull() ? QStringLiteral("UnknownCategory") : data.value("Category"), static_cast(BaseModel::BaseRole::Category)); QString status = data.value("Status").toString(); if (status == QLatin1String("Active")) { dataItem->setData(Plasma::Types::ItemStatus::ActiveStatus, static_cast(BaseModel::BaseRole::Status)); } else if (status == QLatin1String("NeedsAttention")) { dataItem->setData(Plasma::Types::ItemStatus::NeedsAttentionStatus, static_cast(BaseModel::BaseRole::Status)); } else { dataItem->setData(Plasma::Types::ItemStatus::PassiveStatus, static_cast(BaseModel::BaseRole::Status)); } dataItem->setData(sourceName, static_cast(Role::DataEngineSource)); updateItemData(dataItem, data, Role::AttentionIcon); updateItemData(dataItem, data, Role::AttentionIconName); updateItemData(dataItem, data, Role::AttentionMovieName); updateItemData(dataItem, data, Role::Category); updateItemData(dataItem, data, Role::Icon); updateItemData(dataItem, data, Role::IconName); updateItemData(dataItem, data, Role::IconThemePath); updateItemData(dataItem, data, Role::IconsChanged); updateItemData(dataItem, data, Role::Id); updateItemData(dataItem, data, Role::ItemIsMenu); updateItemData(dataItem, data, Role::OverlayIconName); updateItemData(dataItem, data, Role::Status); updateItemData(dataItem, data, Role::StatusChanged); updateItemData(dataItem, data, Role::Title); updateItemData(dataItem, data, Role::TitleChanged); updateItemData(dataItem, data, Role::ToolTipChanged); - updateItemData(dataItem, data, Role::ToolTipIcon); updateItemData(dataItem, data, Role::ToolTipSubTitle); updateItemData(dataItem, data, Role::ToolTipTitle); updateItemData(dataItem, data, Role::WindowId); if (!m_sources.contains(sourceName)) { m_sources.append(sourceName); appendRow(dataItem); } } void StatusNotifierModel::updateItemData(QStandardItem *dataItem, const Plasma::DataEngine::Data &data, const Role role) { int roleId = static_cast(role); dataItem->setData(data.value(roleNames().value(roleId)), roleId); } SystemTrayModel::SystemTrayModel(QObject *parent) : KConcatenateRowsProxyModel(parent) { m_roleNames = KConcatenateRowsProxyModel::roleNames(); } QHash SystemTrayModel::roleNames() const { return m_roleNames; } void SystemTrayModel::addSourceModel(QAbstractItemModel *sourceModel) { QHashIterator it(sourceModel->roleNames()); while (it.hasNext()) { it.next(); if (!m_roleNames.contains(it.key())) { m_roleNames.insert(it.key(), it.value()); } } KConcatenateRowsProxyModel::addSourceModel(sourceModel); } diff --git a/applets/systemtray/systemtraymodel.h b/applets/systemtray/systemtraymodel.h index 2c86f3407..7598fad5e 100644 --- a/applets/systemtray/systemtraymodel.h +++ b/applets/systemtray/systemtraymodel.h @@ -1,146 +1,145 @@ /*************************************************************************** * Copyright (C) 2019 Konrad Materka * * * * 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 SYSTEMTRAYMODEL_H #define SYSTEMTRAYMODEL_H #include #include #include #include namespace Plasma { class Applet; } class BaseModel: public QStandardItemModel { Q_OBJECT public: enum class BaseRole { ItemType = Qt::UserRole + 1, ItemId, CanRender, Category, Status, EffectiveStatus, LastBaseRole }; explicit BaseModel(QObject *parent = nullptr); QHash roleNames() const override; public slots: void onConfigurationChanged(const KConfigGroup &config); private slots: void onRowsInserted(const QModelIndex &parent, int first, int last); void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); private: void updateEffectiveStatus(QStandardItem *dataItem); Plasma::Types::ItemStatus calculateEffectiveStatus(QStandardItem *dataItem); Plasma::Types::ItemStatus readStatus(QStandardItem *dataItem) const; bool m_showAllItems; QStringList m_shownItems; QStringList m_hiddenItems; }; class PlasmoidModel: public BaseModel { Q_OBJECT public: enum class Role { Applet = static_cast(BaseModel::BaseRole::LastBaseRole) + 1, HasApplet }; explicit PlasmoidModel(QObject *parent = nullptr); QHash roleNames() const override; public slots: void addApplet(Plasma::Applet *applet); void removeApplet(Plasma::Applet *applet); }; class StatusNotifierModel : public BaseModel, public Plasma::DataEngineConsumer { Q_OBJECT public: enum class Role { DataEngineSource = static_cast(BaseModel::BaseRole::LastBaseRole) + 100, AttentionIcon, AttentionIconName, AttentionMovieName, Category, Icon, IconName, IconThemePath, IconsChanged, Id, ItemIsMenu, OverlayIconName, Status, StatusChanged, Title, TitleChanged, ToolTipChanged, - ToolTipIcon, ToolTipSubTitle, ToolTipTitle, WindowId }; StatusNotifierModel(QObject* parent); QHash roleNames() const override; Plasma::Service *serviceForSource(const QString &source); public slots: void addSource(const QString &source); void removeSource(const QString &source); void dataUpdated(const QString &sourceName, const Plasma::DataEngine::Data &data); private: void updateItemData(QStandardItem *dataItem, const Plasma::DataEngine::Data &data, const Role role); Plasma::DataEngine *m_dataEngine = nullptr; QStringList m_sources; QHash m_services; }; class SystemTrayModel : public KConcatenateRowsProxyModel { Q_OBJECT public: explicit SystemTrayModel(QObject *parent = nullptr); QHash roleNames() const override; void addSourceModel(QAbstractItemModel *sourceModel); private: QHash m_roleNames; }; #endif // SYSTEMTRAYMODEL_H