Commit c8deafbb authored by Marco Martin's avatar Marco Martin

Redesign of system monitor plasmoids

Summary:
Those plasmoids are intended to replace the old systemmonitor plasmoids
They are based upon the new ksysguard daemon: see D28333 and D28141

It has pluggable presets and sensor "faces" which are available from the KDE store

Every preset is available as a separate plasmoid.
By default are installed ones to replace
roughly one by one the existing systemmonitor plasmoids so systems that use it
will get the new ones in the updates

Depends on D28922

Test Plan: {F8209642}

Reviewers: #plasma

Subscribers: alexde, ngraham, davidedmundson, mmustac, ahiemstra, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D28487
parent d2c57378
install(DIRECTORY common/ DESTINATION ${PLASMA_DATA_INSTALL_DIR}/plasmoids/org.kde.plasma.systemmonitor.net)
plasma_install_package(net org.kde.plasma.systemmonitor.net)
add_subdirectory(systemmonitor)
install(DIRECTORY common/ DESTINATION ${PLASMA_DATA_INSTALL_DIR}/plasmoids/org.kde.plasma.systemmonitor.cpu)
# Systemmonitor presets
plasma_install_package(coreusage org.kde.plasma.systemmonitor.cpucore)
plasma_install_package(cpu org.kde.plasma.systemmonitor.cpu)
install(DIRECTORY common/ DESTINATION ${PLASMA_DATA_INSTALL_DIR}/plasmoids/org.kde.plasma.systemmonitor.diskactivity)
plasma_install_package(diskactivity org.kde.plasma.systemmonitor.diskactivity)
install(DIRECTORY common/ DESTINATION ${PLASMA_DATA_INSTALL_DIR}/plasmoids/org.kde.plasma.systemmonitor.memory)
plasma_install_package(memory org.kde.plasma.systemmonitor.memory)
install(DIRECTORY common/ DESTINATION ${PLASMA_DATA_INSTALL_DIR}/plasmoids/org.kde.plasma.systemmonitor.diskusage)
plasma_install_package(diskusage org.kde.plasma.systemmonitor.diskusage)
plasma_install_package(diskactivity org.kde.plasma.systemmonitor.diskactivity)
plasma_install_package(net org.kde.plasma.systemmonitor.net)
/*
* Copyright 2014 Marco Martin <mart@kde.org>
*
*
* 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 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.0
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
id: rootItem
signal sourceAdded(string source)
property Component delegate
width: units.gridUnit * 10
height: units.gridUnit * 10
Plasmoid.preferredRepresentation: plasmoid.fullRepresentation
Layout.minimumWidth: units.gridUnit * 12 * (plasmoid.formFactor === PlasmaCore.Types.Horizontal ? sourcesModel.count : 1)
Layout.minimumHeight: units.gridUnit * 4 * (plasmoid.formFactor === PlasmaCore.Types.Vertical ? sourcesModel.count : 1)
Layout.preferredHeight: Layout.minimumHeight
function addSource(source1, friendlyName1, source2, friendlyName2) {
var found = false;
for (var i = 0; i < sourcesModel.count; ++i) {
var obj = sourcesModel.get(i);
if (obj.source1 === encodeURIComponent(source1) &&
obj.source2 === encodeURIComponent(source2)) {
found = true;
break;
}
}
if (found) {
return;
}
smSource.connectSource(source1);
if (source2) {
smSource.connectSource(source2);
}
sourcesModel.append(
{"source1": encodeURIComponent(source1),
"friendlyName1": friendlyName1,
"source2": encodeURIComponent(source2),
"friendlyName2": friendlyName2,
"dataSource": smSource});
}
function showSource(source) {
if (plasmoid.configuration.sources && plasmoid.configuration.sources.length > 0) {
return plasmoid.configuration.sources.indexOf(encodeURIComponent(source)) !== -1;
} else {
return sourceDefaultEnable(source);
}
}
function sourceDefaultEnable(source) {
return true;
}
ListModel {
id: sourcesModel
}
Component.onCompleted: {
for (var i in smSource.sources) {
smSource.sourceAdded(smSource.sources[i]);
}
}
PlasmaCore.DataSource {
id: smSource
engine: "systemmonitor"
interval: plasmoid.configuration.updateInterval
onSourceAdded: {
if (showSource(source)) {
rootItem.sourceAdded(source);
}
}
onSourceRemoved: {
for (var i = sourcesModel.count - 1; i >= 0; --i) {
var obj = sourcesModel.get(i);
if (obj.source1 === source || obj.source2 === source) {
sourcesModel.remove(i);
}
}
smSource.disconnectSource(source);
}
}
Connections {
target: plasmoid.configuration
onSourcesChanged: {
if (plasmoid.configuration.sources.length === 0) {
for (var i in smSource.sources) {
var source = smSource.sources[i];
smSource.sourceAdded(source);
}
} else {
var sourcesToRemove = [];
for (var i = sourcesModel.count - 1; i >= 0; --i) {
var obj = sourcesModel.get(i);
if (plasmoid.configuration.sources.indexOf(encodeURIComponent(obj.source1)) === -1) {
sourcesToRemove.push(obj.source1);
}
}
for (i = 0; i < sourcesToRemove.length; ++i) {
smSource.sourceRemoved(sourcesToRemove[i]);
}
for (var i in plasmoid.configuration.sources) {
var source = decodeURIComponent(plasmoid.configuration.sources[i]);
smSource.sourceAdded(source);
}
}
}
}
PlasmaExtras.Heading {
id: heading
width: parent.width
level: 2
text: plasmoid.title
visible: plasmoid.formFactor !== PlasmaCore.Types.Horizontal && plasmoid.formFactor !== PlasmaCore.Types.Vertical
}
GridLayout {
rows: 1
columns: 1
flow: plasmoid.formFactor !== PlasmaCore.Types.Horizontal ? GridLayout.LeftToRight : GridLayout.TopToBottom
anchors {
top: heading.visible ? heading.bottom : parent.top
bottom: parent.bottom
}
width: parent.width
Repeater {
model: sourcesModel
delegate: rootItem.delegate
}
}
}
/*
* Copyright 2013 Bhushan Shah <bhush94@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 2.010-1301, USA.
*/
import QtQuick 2.5
import QtQuick.Controls 2.5 as QQC2
import QtQuick.Layouts 1.3
import org.kde.kirigami 2.5 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: iconsPage
width: childrenRect.width
height: childrenRect.height
implicitWidth: formLayout.implicitWidth
implicitHeight: formLayout.implicitHeight
property var cfg_sources: []
function sourcesChanged() {
if (! cfg_sources) { cfg_sources = [] }
if (cfg_sources.length == 0) {
for (var i in dataSourcesColumn.children) {
var child = dataSourcesColumn.children[i];
if (child.checked !== undefined) {
child.checked = sourceDefaultEnable(child.source);
}
}
} else {
for (var i in dataSourcesColumn.children) {
var child = dataSourcesColumn.children[i];
if (child.checked !== undefined) {
child.checked = cfg_sources.indexOf(child.source) !== -1;
}
}
}
}
function sourceDefaultEnable(source) {
return true;
}
onCfg_sourcesChanged: {
sourcesChanged();
}
property int cfg_updateInterval
signal sourceAdded(string source)
function addSource(source, friendlyName) {
var found = false;
for (var i = 0; i < sourcesModel.count; ++i) {
var obj = sourcesModel.get(i);
if (obj.source === source) {
found = true;
break;
}
}
if (found) {
return;
}
sourcesModel.append(
{"source": encodeURIComponent(source),
"friendlyName": friendlyName});
}
PlasmaCore.DataSource {
id: smSource
engine: "systemmonitor"
onSourceAdded: {
iconsPage.sourceAdded(source);
}
onSourceRemoved: {
for (var i = sourcesModel.count - 1; i >= 0; --i) {
var obj = sourcesModel.get(i);
if (obj.source === source) {
sourcesModel.remove(i);
}
}
}
}
Component.onCompleted: {
for (var i in smSource.sources) {
var source = smSource.sources[i];
iconsPage.sourceAdded(source);
}
sourcesChanged();
}
ListModel {
id: sourcesModel
}
Kirigami.FormLayout {
id: formLayout
anchors.left: parent.left
anchors.right: parent.right
QQC2.SpinBox {
id: updateIntervalSpinBox
Kirigami.FormData.label: i18n("Update interval:")
from: 100
stepSize: 100
to: 1000000
editable: true
validator: DoubleValidator {
bottom: spinbox.from
top: spinbox.to
}
textFromValue: function(value) {
var seconds = value / 1000
return i18ncp("SpinBox text", "%1 second", "%1 seconds", seconds.toFixed(1))
}
valueFromText: function(text) {
return parseFloat(text) * 1000
}
value: cfg_updateInterval
onValueModified: cfg_updateInterval = value
}
Item {
Kirigami.FormData.isSection: true
}
ColumnLayout {
id: dataSourcesColumn
Kirigami.FormData.label: i18n("Show:")
Kirigami.FormData.buddyFor: children[1] // 0 is the Repeater
Repeater {
id: repeater
model: sourcesModel
QQC2.CheckBox {
id: checkBox
text: model.friendlyName
property string source: model.source
onCheckedChanged: {
if (checked) {
if (cfg_sources.indexOf(model.source) == -1) {
cfg_sources.push(model.source);
}
} else {
var idx = cfg_sources.indexOf(model.source);
if (cfg_sources.length !== 1) { // This condition prohibits turning off the last item from the list.
if (idx !== -1) {
cfg_sources.splice(idx, 1);
}
}
}
cfg_sourcesChanged();
}
}
}
}
}
}
/*
* Copyright 2015 Marco Martin <mart@kde.org>
*
*
* 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 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.0
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
KQuickAddons.Plotter {
id: plotter
property string sensorName: model.friendlyName1
Layout.fillWidth: true
Layout.fillHeight: true
horizontalGridLineCount: 0
function cycle(color, degrees) {
var min = Math.min(color.r, Math.min(color.g, color.b));
var max = Math.max(color.r, Math.max(color.g, color.b));
var c = max - min;
var h;
if (c === 0) {
h = 0
} else if (max === color.r) {
h = ((color.g - color.b) / c) % 6;
} else if (max === color.g) {
h = ((color.b - color.r) / c) + 2;
} else if (max === color.b) {
h = ((color.r - color.g) / c) + 4;
}
var hue = (1/6) * h + (degrees/360);
var saturation = c / (1 - Math.abs(2 * ((max+min)/2) - 1));
var lightness = (max + min)/2;
return Qt.hsla(hue, saturation, lightness, 1.0);
}
property string downloadColor: theme.highlightColor
property string uploadColor: cycle(theme.highlightColor, -90)
dataSets: [
KQuickAddons.PlotData {
color: downloadColor
},
KQuickAddons.PlotData {
color: uploadColor
}
]
PlasmaComponents.Label {
id: nameLabel
anchors {
left: parent.left
top: parent.top
}
}
PlasmaComponents.Label {
id: speedLabel
wrapMode: Text.WordWrap
visible: plasmoid.formFactor !== PlasmaCore.Types.Vertical
anchors {
right: parent.right
}
}
Connections {
target: model.dataSource
onNewData: {
if (sourceName.indexOf(decodeURIComponent(model.source1)) !== 0 && sourceName.indexOf(decodeURIComponent(model.source2)) !== 0) {
return;
}
var data1 = model.dataSource.data[decodeURIComponent(model.source2)];
var data2 = model.dataSource.data[decodeURIComponent(model.source1)];
if (data1 === undefined || data1.value === undefined ||
data2 === undefined || data2.value === undefined) {
return;
}
plotter.addSample([data1.value, data2.value]);
if (plasmoid.formFactor !== PlasmaCore.Types.Vertical) {
nameLabel.text = plotter.sensorName
speedLabel.text = i18n("<font color='%1'>⬇</font> %2 | <font color='%3'>⬆</font> %4",
downloadColor,
formatData(data1),
uploadColor,
formatData(data2))
} else {
nameLabel.text = plotter.sensorName+ "\n" + formatData(data1) + "\n" + formatData(data2)
speedLabel.text = ""
}
}
}
}
/*
* Copyright 2015 Marco Martin <mart@kde.org>
*
*
* 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 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.0
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.kquickcontrolsaddons 2.0 as KQuickAddons
KQuickAddons.Plotter {
id: plotter
property string sensorName: model.friendlyName1
Layout.fillWidth: true
Layout.fillHeight: true
//FIXME: doesn't seem to properly fill otherwise
Layout.preferredHeight: parent.height
horizontalGridLineCount: 0
dataSets: [
KQuickAddons.PlotData {
color: theme.highlightColor
}
]
PlasmaComponents.Label {
id: nameLabel
anchors {
left: parent.left
top: parent.top
}
}
PlasmaComponents.Label {
id: speedLabel
wrapMode: Text.WordWrap
visible: plasmoid.formFactor !== PlasmaCore.Types.Vertical
anchors {
right: parent.right
}
}
Connections {
target: model.dataSource
onNewData: {
if (sourceName.indexOf(decodeURIComponent(model.source1)) !== 0) {
return;
}
var data1 = model.dataSource.data[decodeURIComponent(model.source1)];
if (data1 === undefined || data1.value === undefined) {
return;
}
plotter.addSample([data1.value]);
if (plasmoid.formFactor !== PlasmaCore.Types.Vertical) {
nameLabel.text = plotter.sensorName
speedLabel.text = formatData(data1)
} else {
nameLabel.text = plotter.sensorName+ "\n" + formatData(data1)
speedLabel.text = ""
}
}
}
}
[Config]
chartFace=org.kde.ksysguard.barchart
highPrioritySensorIds=["cpu/cpu.*/TotalLoad"]
totalSensors=["cpu/system/TotalLoad"]
textOnlySensorIds=["cpu/system/loadavg1","cpu/system/loadavg5"]
[FaceConfig]
rangeAuto=false
rangeFrom=0
rangeTo=100
[Desktop Entry]
Name=Individual Core Usage
Name[de]=Einzelne Prozessorkernbelastung
Comment=System monitor Widget that shows usage of individual CPU cores
Type=Service
Icon=ksysguardd
X-KDE-ServiceTypes=Plasma/Applet
X-Plasma-API=declarativeappletscript
X-Plasma-MainScript=ui/main.qml
X-Plasma-Provides=org.kde.plasma.systemmonitor
X-Plasma-RootPath=org.kde.plasma.systemmonitor
X-KDE-PluginInfo-Author=Kai Uwe Broulik