From e1a38e1a5cad39c906cbfb90fa760eca15f8f81c Mon Sep 17 00:00:00 2001 From: Michal Bukovsky Date: Thu, 30 Nov 2017 06:23:49 +0100 Subject: [PATCH] add executable source, add new monitor types, ... --- plasmoid/contents/code/utils.js | 67 ++++++ plasmoid/contents/config/config.qml | 14 +- plasmoid/contents/config/main.xml | 14 +- plasmoid/contents/ui/BarMonitor.qml | 103 +++++++++ plasmoid/contents/ui/CircularMonitor.qml | 27 ++- plasmoid/contents/ui/CompactBarMonitor.qml | 60 +++++ .../ui/ConditionallyLoadedMonitor.qml | 59 +++++ plasmoid/contents/ui/Config.qml | 47 +++- plasmoid/contents/ui/ExampleConfig.qml | 185 +++++++++++++++ .../ui/ExecutableDataSourceConfig.qml | 214 ++++++++++++++++++ plasmoid/contents/ui/NumberMonitor.qml | 87 +++++++ plasmoid/contents/ui/PlotterMonitor.qml | 82 +++++++ ....qml => SystemMonitorDataSourceConfig.qml} | 27 +-- plasmoid/contents/ui/main.qml | 156 ++++++++----- 14 files changed, 1066 insertions(+), 76 deletions(-) create mode 100644 plasmoid/contents/code/utils.js create mode 100644 plasmoid/contents/ui/BarMonitor.qml create mode 100644 plasmoid/contents/ui/CompactBarMonitor.qml create mode 100644 plasmoid/contents/ui/ConditionallyLoadedMonitor.qml create mode 100644 plasmoid/contents/ui/ExampleConfig.qml create mode 100644 plasmoid/contents/ui/ExecutableDataSourceConfig.qml create mode 100644 plasmoid/contents/ui/NumberMonitor.qml create mode 100644 plasmoid/contents/ui/PlotterMonitor.qml rename plasmoid/contents/ui/{DataSourcesConfig.qml => SystemMonitorDataSourceConfig.qml} (88%) diff --git a/plasmoid/contents/code/utils.js b/plasmoid/contents/code/utils.js new file mode 100644 index 0000000..1cd0006 --- /dev/null +++ b/plasmoid/contents/code/utils.js @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +function to_string(value) { + return Number(value).toLocaleString(Qt.locale(), "f") +} + +function format_number(conf, value) { + var value_units = [ + {"unit": "Y", "exp": Math.pow(10, 24)}, + {"unit": "Z", "exp": Math.pow(10, 21)}, + {"unit": "E", "exp": Math.pow(10, 18)}, + {"unit": "P", "exp": Math.pow(10, 15)}, + {"unit": "T", "exp": Math.pow(10, 12)}, + {"unit": "G", "exp": Math.pow(10, 9)}, + {"unit": "M", "exp": Math.pow(10, 6)}, + {"unit": "k", "exp": Math.pow(10, 3)}, + {"unit": "", "exp": Math.pow(10, 0)}, + {"unit": "m", "exp": Math.pow(10, -3)}, + {"unit": "u", "exp": Math.pow(10, -6)}, + {"unit": "n", "exp": Math.pow(10, -9)}, + {"unit": "p", "exp": Math.pow(10, -12)}, + {"unit": "f", "exp": Math.pow(10, -15)}, + {"unit": "a", "exp": Math.pow(10, -18)}, + ] + + for (var i = 0; i < value_units.length; ++i) { + var value_unit = value_units[i] + var fixed_value = value * conf.multiplier + if (fixed_value > value_unit.exp) + return to_string(fixed_value / value_unit.exp) + value_unit.unit + } + return "0" +} + +function get_label(conf, orig_values) { + if (!conf.use_value_as_label) + return conf.label + var label = 0.0 + for (var i = 0; i < orig_values.length; ++i) + label += orig_values[i] + return format_number(conf, label) +} + +function is_label_visible(conf) { + return conf.use_value_as_label + || (conf.label && conf.label.length) +} + +function get_height(conf, base) { + return base.height - theme.mSize(theme.defaultFont).height * (is_label_visible(conf)? 1: 0) +} + diff --git a/plasmoid/contents/config/config.qml b/plasmoid/contents/config/config.qml index be37022..88c62a3 100644 --- a/plasmoid/contents/config/config.qml +++ b/plasmoid/contents/config/config.qml @@ -25,9 +25,19 @@ ConfigModel { source: "Config.qml" } ConfigCategory { - name: i18n("Data Sources") + name: i18n("System Monitor Data Source") icon: "utilities-system-monitor" - source: "DataSourcesConfig.qml" + source: "SystemMonitorDataSourceConfig.qml" + } + ConfigCategory { + name: i18n("Executabale Data Source") + icon: "application-x-executable" + source: "ExecutableDataSourceConfig.qml" + } + ConfigCategory { + name: i18n("Examples") + icon: "user-desktop" + source: "ExampleConfig.qml" } } diff --git a/plasmoid/contents/config/main.xml b/plasmoid/contents/config/main.xml index 23b6b45..7850a1e 100644 --- a/plasmoid/contents/config/main.xml +++ b/plasmoid/contents/config/main.xml @@ -9,9 +9,18 @@ + + false + + + 0 + 0.0 + + 1.0 + 1.0 @@ -30,9 +39,12 @@ - + + + 0.0 + diff --git a/plasmoid/contents/ui/BarMonitor.qml b/plasmoid/contents/ui/BarMonitor.qml new file mode 100644 index 0000000..0df675e --- /dev/null +++ b/plasmoid/contents/ui/BarMonitor.qml @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2014 Martin Yrjölä + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../code/utils.js" as Utils + +Item { + id: bar_monitor + + anchors.fill: parent + height: childrenRect.height + + property var orig_values + property var values + + ColumnLayout { + width: parent.width + + Item { + id: bar_row + + height: Utils.get_height(plasmoid.configuration, bar_monitor) + + Rectangle { + id: bar_border + + height: Utils.get_height(plasmoid.configuration, bar_monitor) + width: bar_monitor.width + + color: "transparent" + + radius: 3 + opacity: .4 + + border { + color: theme.textColor + width: 1 + } + } + + Repeater { + id: bar_repeater + model: values.length + + Rectangle { + color: plasmoid.configuration.colors[index] + height: (bar_border.height - (bar_border.border.width * 2)) * bar_monitor.values[index] + width: bar_border.width - (bar_border.border.width * 2) + z: -1 + anchors { + bottom: index == 0 + ? bar_border.bottom + : bar_repeater.itemAt(index - 1).top + bottomMargin: index == 0 + ? bar_border.border.width + : 0 + } + } + } + } + + PlasmaComponents.Label { + id: bar_label + + width: bar_border.width + Layout.maximumWidth: bar_border.width + visible: Utils.is_label_visible(plasmoid.configuration) + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + + onVisibleChanged: { + bar_row.height = Utils.get_height(plasmoid.configuration, bar_monitor) + bar_monitor.height = Utils.get_height(plasmoid.configuration, bar_monitor) + } + + anchors { + top: bar_row.bottom + horizontalCenter: parent.horizontalCenter + } + + text: Utils.get_label(plasmoid.configuration, orig_values) + } + } +} + diff --git a/plasmoid/contents/ui/CircularMonitor.qml b/plasmoid/contents/ui/CircularMonitor.qml index cabeb62..3aa057d 100644 --- a/plasmoid/contents/ui/CircularMonitor.qml +++ b/plasmoid/contents/ui/CircularMonitor.qml @@ -18,9 +18,14 @@ import QtQuick 2.0 import QtQuick.Layouts 1.1 +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../code/utils.js" as Utils Item { - property alias colors: canvas.colors + id: circular_monitor + + property var orig_values property alias values: canvas.values anchors { @@ -43,7 +48,6 @@ Item { property real alpha: 1.0 property var values - property var colors // This fixes edge bleeding readonly property double filler: 0.01 @@ -66,7 +70,7 @@ Item { // draw the sectors for (var i = 0; i < values.length; i++) { var radians = values[i] * 2 * Math.PI - ctx.fillStyle = colors[i] + ctx.fillStyle = plasmoid.configuration.colors[i] ctx.beginPath() ctx.arc(width / 2, height / 2, min / 2.03, currentRadian, currentRadian + radians + filler, false) ctx.arc(width / 2, height / 2, min / 3.5, currentRadian + radians + filler, currentRadian, true) @@ -89,5 +93,22 @@ Item { ctx.restore() } } + + // the label if requested + PlasmaComponents.Label { + id: label + width: parent.width - (Math.min(canvas.height, canvas.width) / 2.03 - Math.min(canvas.height, canvas.width) / 3.5) * 2 + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + + // tells the label to be centered in parent (in the centre of CircularMonitor) + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + + // the value + text: Utils.get_label(plasmoid.configuration, orig_values) + } } diff --git a/plasmoid/contents/ui/CompactBarMonitor.qml b/plasmoid/contents/ui/CompactBarMonitor.qml new file mode 100644 index 0000000..f466040 --- /dev/null +++ b/plasmoid/contents/ui/CompactBarMonitor.qml @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2014 Martin Yrjölä + * Copyright (C) 2015 Joshua Worth + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +Item { + id: barMonitor + + property var colors + property var proportions: [] + + Layout.fillHeight: true + Layout.fillWidth: true + + Rectangle { + id: barBorder + anchors.fill: parent + opacity: 0 + } + + Repeater { + id: barRepeater + model: proportions.length + Rectangle { + color: barMonitor.colors[index] + height: barBorder.height * barMonitor.proportions[index] + width: barBorder.width + anchors { + bottom: index == 0 ? barBorder.bottom : barRepeater.itemAt(index-1).top + bottomMargin: index == 0 ? barBorder.border.width : 0 + } + + LinearGradient { + anchors.fill: parent + end: Qt.point(width, 0) + gradient: Gradient { + GradientStop { position: 0.0; color: "#60ffffff" } + GradientStop { position: 1.0; color: "transparent" } + } + } + } + } +} diff --git a/plasmoid/contents/ui/ConditionallyLoadedMonitor.qml b/plasmoid/contents/ui/ConditionallyLoadedMonitor.qml new file mode 100644 index 0000000..d9da35f --- /dev/null +++ b/plasmoid/contents/ui/ConditionallyLoadedMonitor.qml @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 Martin Yrjölä + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 + +Item { + property var values + property var orig_values + + Layout.fillWidth: true + Layout.fillHeight: true + + function source_url() { + switch (plasmoid.configuration.monitor_type) { + default: + case 0: + return "CircularMonitor.qml"; + case 1: + return "BarMonitor.qml"; + case 2: + return "PlotterMonitor.qml"; + case 3: + return "NumberMonitor.qml"; + } + } + + Loader { + id: loader + active: visible + anchors.fill: parent + source: source_url() + onLoaded: { + loader.item.values = Qt.binding(function() { return values }) + loader.item.orig_values = Qt.binding(function() { return orig_values }) + } + } + + Connections { + target: plasmoid.configuration + onColorsChanged: loader.setSource(source_url(), {}) + } +} + diff --git a/plasmoid/contents/ui/Config.qml b/plasmoid/contents/ui/Config.qml index 8c090fa..d4bd8a6 100644 --- a/plasmoid/contents/ui/Config.qml +++ b/plasmoid/contents/ui/Config.qml @@ -26,8 +26,11 @@ Item { id: config property alias cfg_label: label_text_field.text + property alias cfg_monitor_type: type_combo.currentIndex property alias cfg_update_interval: update_interval_spinbox.value property alias cfg_max_value: max_value_spinbox.value + property alias cfg_multiplier: multiplier_spinbox.value + property alias cfg_use_value_as_label: use_value_as_label_checkbox.checked property string cfg_default_color GridLayout { @@ -44,7 +47,33 @@ Item { QtControls.TextField { id: label_text_field - font.capitalization: Font.SmallCaps + onTextChanged: { + cfg_use_value_as_label = false + } + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width + } + + QtControls.Label { + text: i18n("Use Value as Label:") + Layout.alignment: Qt.AlignRight + } + + QtControls.CheckBox { + id: use_value_as_label_checkbox + onCheckedChanged: { + label_text_field.enabled = !checked + } + } + + QtControls.Label { + text: i18n("Type:") + Layout.alignment: Qt.AlignRight + } + + QtControls.ComboBox { + id: type_combo + model: ["circular", "bar", "plotter", "number"] + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width } QtControls.Label { @@ -58,6 +87,7 @@ Item { onColorSelected: { cfg_default_color = chosen_color.toString() } + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width } QtControls.Label { @@ -70,6 +100,20 @@ Item { minimumValue: 0.0 maximumValue: Number.MAX_VALUE stepSize: 1.0 + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width + } + + QtControls.Label { + text: i18n("Value Multiplier:") + Layout.alignment: Qt.AlignRight + } + + QtControls.SpinBox { + id: multiplier_spinbox + decimals: 6 + minimumValue: Number.MIN_VALUE + maximumValue: Number.MAX_VALUE + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width } QtControls.Label { @@ -84,6 +128,7 @@ Item { minimumValue: 0.1 maximumValue: Number.MAX_VALUE stepSize: 0.1 + Layout.preferredWidth: 20 * theme.mSize(theme.defaultFont).width } } } diff --git a/plasmoid/contents/ui/ExampleConfig.qml b/plasmoid/contents/ui/ExampleConfig.qml new file mode 100644 index 0000000..754502a --- /dev/null +++ b/plasmoid/contents/ui/ExampleConfig.qml @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.2 as QtControls + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: examples + + property var configs: [ + { + "description": "CPU circular monitor", + "config": { + "label": "cpu", + "monitor_type": 0, + "names": ["sys.cpu/system/user", "sys.cpu/system/sys", "sys.cpu/system/nice", "sys.cpu/system/wait"], + "labels": ["", "", "", ""], + "colors": ["limegreen", "royalblue", "chocolate", "crimson"], + "max_value": 100, + "last_filter": "cpu/system", + } + }, { + "description": "Memory bar monitor, set the amount of memory of your computer to max_value field in kilobytes", + "config": { + "label": "mem", + "monitor_type": 1, + "names": ["sys.mem/physical/application", "sys.mem/physical/buf", "sys.mem/physical/cached"], + "labels": ["", "", ""], + "colors": ["limegreen", "royalblue", "chocolate"], + "max_value": 16330816, + "multiplier": 1000, + "last_filter": "mem/physical", + } + }, { + "description": "Processor temperature monitor for SkyLake chipset", + "config": { + "label": "temp", + "monitor_type": 0, + "names": ["sys.acpi/Thermal_Zone/6-pch_skylake/Temperature"], + "labels": [""], + "colors": ["limegreen"], + "max_value": 100, + "last_filter": "acpi/Thermal_Zone", + } + }, { + "description": "Battery charge monitor", + "config": { + "label": "bat", + "monitor_type": 0, + "names": ["sys.acpi/battery/0/batterycharge"], + "labels": [""], + "colors": ["limegreen"], + "max_value": 100, + "last_filter": "acpi/battery", + } + }, { + "description": "Loopback network interface traffic plotting monitor, change to you network interface", + "config": { + "label": "lo", + "monitor_type": 2, + "names": ["sys.network/interfaces/lo/receiver/data", "sys.network/interfaces/lo/transmitter/data"], + "labels": ["", ""], + "colors": ["limegreen", "royalblue"], + "last_filter": "network/interfaces", + } + }, { + "description": "System load plotting monitor", + "config": { + "label": "load", + "monitor_type": 2, + "names": ["sys.cpu/system/TotalLoad"], + "labels": [""], + "colors": ["limegreen"], + "last_filter": "cpu/system", + } + }, { + "description": "Ping time to 8.8.8.8", + "config": { + "label": "ping", + "monitor_type": 2, + "multiplier": 0.001, + "names": ["exe.ping -nqc 1 8.8.8.8 -W 1 | cut -s -f 5 -d/"], + "labels": ["ping 8.8.8.8"], + "colors": ["limegreen"], + "update_interval": 2 + } + } + ] + + Column { + anchors.fill: parent + spacing: 20 + + Text { + id: description_label + width: parent.width + color: theme.textColor + textFormat: Text.StyledText + wrapMode: Text.WordWrap + text: "Here are some examples that show you how to configure SysMon and what can be done with it. " + + "Just click on any item bellow and you will see the result immediately. After that go to " + + "other configuration and data sources tabs to see how it is done." + } + + ListView { + id: view + height: parent.height - description_label.height + width: parent.width + model: configs + spacing: 10 + + delegate: Rectangle { + width: parent.width + height: Math.round(theme.mSize(theme.defaultFont).height * 1.6) + color: theme.backgroundColor + border { + color: Qt.lighter(theme.backgroundColor) + width: 1 + } + + Text { + id: text_view + width: parent.width + color: theme.textColor + text: modelData.description + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: 10 + } + + Behavior on color { + SequentialAnimation { + loops: 3 + ColorAnimation { + from: theme.textColor + to: theme.highlightColor + duration: 300 + } + ColorAnimation { + from: theme.highlightColor + to: theme.textColor + duration: 300 + } + } + } + } + + MouseArea { + id: mousearea + anchors.fill: parent + property Text text + onClicked: { + text.color = theme.highlightColor + for (var name in modelData.config) + plasmoid.configuration[name] = modelData.config[name] + } + } + + Component.onCompleted: { + mousearea.text = text_view + } + } + } + } +} + diff --git a/plasmoid/contents/ui/ExecutableDataSourceConfig.qml b/plasmoid/contents/ui/ExecutableDataSourceConfig.qml new file mode 100644 index 0000000..1c4db12 --- /dev/null +++ b/plasmoid/contents/ui/ExecutableDataSourceConfig.qml @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.0 +import QtQuick.Layouts 1.0 +import QtQuick.Controls 1.2 as QtControls + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: config + + signal configurationChanged(var model, int remove) + + property var cfg_names: [] + property var cfg_colors: [] + property var cfg_labels: [] + + onConfigurationChanged: { + cfg_colors.length = cfg_names.length + cfg_labels.length = cfg_names.length + + var exe_name = "exe." + model.command + if (!remove) { + var i = cfg_names.indexOf(exe_name) + if (i == -1) { + cfg_names.push(exe_name) + cfg_colors.push(model.color) + cfg_labels.push(model.label) + } else cfg_colors[i] = model.color + } else { + var i = cfg_names.indexOf(exe_name) + if (i != -1) { + cfg_names.splice(i, 1) + cfg_colors.splice(i, 1) + cfg_labels.splice(i, 1) + } + } + } + + Component.onCompleted: { + cfg_names = plasmoid.configuration.names.slice() + cfg_colors = plasmoid.configuration.colors.slice() + cfg_labels = plasmoid.configuration.labels.slice() + + for (var i = 0; i < cfg_names.length; ++i) { + var exe_name = plasmoid.configuration.names[i] + if (exe_name.substring(0, 4) == "exe.") { + exe_sources_model.append({ + "label": cfg_labels[i], + "command": exe_name.substring(4), + "color": cfg_colors[i], + }) + } + } + } + + Column { + width: parent.width + height: parent.height + spacing: 10 + + QtControls.TableView { + id: exe_sources_view + + height: parent.height - grid_layout.height - 20 + width: parent.width + + selectionMode: QtControls.SelectionMode.NoSelection + + model: ListModel { + id: exe_sources_model + } + + rowDelegate: Rectangle { + height: theme.mSize(theme.defaultFont).height * 1.6 + SystemPalette { + id: row_pallete; + colorGroup: SystemPalette.Active + } + color: { + var base_color = styleData.alternate + ? row_pallete.base + : row_pallete.alternateBase + return styleData.selected + ? row_pallete.highlight + : base_color + } + } + + // the first column with checkbox + QtControls.TableViewColumn { + id: color_col + role: "color" + + title: i18n("Show") + width: theme.mSize(theme.defaultFont).width * 5 + + delegate: Item { + anchors.fill: parent + + ColorPicker { + id: color_picker + activeFocusOnTab: false + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + + chosen_color: model + ? model.color + : plasmoid.configuration.default_color + + onColorSelected: { + if (model) model.color = chosen_color.toString() + configurationChanged(model, false) + } + } + } + } + + QtControls.TableViewColumn { + id: label_col + role: "label" + + title: i18n("Label") + width: theme.mSize(theme.defaultFont).width * 10 + } + + QtControls.TableViewColumn { + id: cmd_col + role: "command" + width: exe_sources_view.width - color_col.width - label_col.width - actions_col.width - 10 + + title: i18n("Command") + } + + QtControls.TableViewColumn { + id: actions_col + width: theme.mSize(theme.defaultFont).width * 7 + + delegate: QtControls.Button { + text: i18n("Delete") + onClicked: { + configurationChanged(model, true) + exe_sources_model.remove(model.index, 1) + } + } + } + } + + GridLayout { + id: grid_layout + + columns: 2 + columnSpacing: 10 + rowSpacing: 10 + width: parent.width + + QtControls.Label { + text: i18n("Label:") + Layout.alignment: Qt.AlignRight + } + + QtControls.TextField { + id: label_text_field + Layout.preferredWidth: command_text_field.placeholderText.length * theme.mSize(theme.defaultFont).width + } + + QtControls.Label { + text: i18n("Command:") + Layout.alignment: Qt.AlignRight + } + + QtControls.TextField { + id: command_text_field + Layout.preferredWidth: placeholderText.length * theme.mSize(theme.defaultFont).width + placeholderText: i18n("The command should print one number to stdout") + } + + QtControls.Button { + text: i18n("Add") + enabled: command_text_field.text.length + onClicked: { + var model = { + "label": label_text_field.text, + "command": command_text_field.text, + "color": plasmoid.configuration.default_color, + } + exe_sources_model.append(model) + configurationChanged(model, false) + label_text_field.text = "" + command_text_field.text = "" + } + } + } + } +} + diff --git a/plasmoid/contents/ui/NumberMonitor.qml b/plasmoid/contents/ui/NumberMonitor.qml new file mode 100644 index 0000000..5d528f8 --- /dev/null +++ b/plasmoid/contents/ui/NumberMonitor.qml @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2014 Martin Yrjölä + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../code/utils.js" as Utils + +Item { + id: number_monitor + + anchors.fill: parent + + property var orig_values: [] + property var values: [] + + ColumnLayout { + width: number_monitor.width + + Item { + id: number_item + height: Utils.get_height(plasmoid.configuration, number_monitor) + Layout.preferredWidth: number_monitor.width + + Grid { + id: number_grid + + columns: Math.ceil(Math.sqrt(values.length)) + height: Utils.get_height(plasmoid.configuration, number_monitor) + width: number_monitor.width + horizontalItemAlignment: Grid.AlignHCenter + verticalItemAlignment: Grid.AlignVCenter + + Repeater { + id: number_repeater + model: orig_values.length + + Text { + height: Math.abs(number_item.height / Math.max(number_grid.children.length / number_grid.columns, 1)) + width: Math.abs(number_item.width / Math.max(number_grid.columns, 1)) + elide: Text.ElideRight + color: plasmoid.configuration.colors[index] + text: Utils.format_number(plasmoid.configuration, orig_values[index]) + } + } + } + } + + PlasmaComponents.Label { + id: number_label + + width: number_monitor.width + Layout.maximumWidth: number_monitor.width + visible: Utils.is_label_visible(plasmoid.configuration) + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + + onVisibleChanged: { + number_item.height = Utils.get_height(plasmoid.configuration, number_monitor) + } + + anchors { + top: number_item.bottom + horizontalCenter: parent.horizontalCenter + } + + text: Utils.get_label(plasmoid.configuration, orig_values) + } + } +} + diff --git a/plasmoid/contents/ui/PlotterMonitor.qml b/plasmoid/contents/ui/PlotterMonitor.qml new file mode 100644 index 0000000..19b4802 --- /dev/null +++ b/plasmoid/contents/ui/PlotterMonitor.qml @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 Michal Bukovský + * + * 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) version 3 or 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, see + */ + +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 + +import "../code/utils.js" as Utils + +Item { + id: plotter_monitor + + property var orig_values + property var values + + onValuesChanged: { + if (plotter.dataSets.length != values.length) + plotter.dataSets = make_data_set() + plotter.addSample(values); + } + + function make_data_set() { + var plot_data = [] + for (var i = 0; i < plasmoid.configuration.colors.length; ++i) { + var data = Qt.createQmlObject("import org.kde.kquickcontrolsaddons 2.0; PlotData {}", plotter, "plot_data_" + i) + data.color = plasmoid.configuration.colors[i] + plot_data.push(data) + } + return plot_data + } + + KQuickAddons.Plotter { + id: plotter + + height: Utils.get_height(plasmoid.configuration, plotter_monitor) + width: parent.width + + horizontalGridLineCount: 0 + + autoRange: true + + dataSets: make_data_set() + } + + // the label if requested + PlasmaComponents.Label { + id: label + + width: plotter.width + visible: Utils.is_label_visible(plasmoid.configuration) + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + + onVisibleChanged: { + plotter.height = Utils.get_height(plasmoid.configuration, plotter_monitor) + } + + anchors { + top: plotter.bottom + horizontalCenter: parent.horizontalCenter + } + + text: Utils.get_label(plasmoid.configuration, orig_values) + } +} + diff --git a/plasmoid/contents/ui/DataSourcesConfig.qml b/plasmoid/contents/ui/SystemMonitorDataSourceConfig.qml similarity index 88% rename from plasmoid/contents/ui/DataSourcesConfig.qml rename to plasmoid/contents/ui/SystemMonitorDataSourceConfig.qml index 4b80866..614d1b9 100644 --- a/plasmoid/contents/ui/DataSourcesConfig.qml +++ b/plasmoid/contents/ui/SystemMonitorDataSourceConfig.qml @@ -29,24 +29,22 @@ Item { property var cfg_names: [] property var cfg_colors: [] - property var cfg_guessed_max_values: [] property alias cfg_last_filter: filter.text onConfigurationChanged: { cfg_colors.length = cfg_names.length + var sys_name = "sys." + model.name if (model.checked) { - var i = cfg_names.indexOf(model.name) + var i = cfg_names.indexOf(sys_name) if (i == -1) { - cfg_names.push(model.name) + cfg_names.push(sys_name) cfg_colors.push(model.color) - cfg_guessed_max_values.push(String(0)) } else cfg_colors[i] = model.color } else { - var i = cfg_names.indexOf(model.name) + var i = cfg_names.indexOf(sys_name) if (i != -1) { cfg_names.splice(i, 1) cfg_colors.splice(i, 1) - cfg_guessed_max_values.splice(i, 1) } } } @@ -56,32 +54,25 @@ Item { engine: "systemmonitor" } - function name_index(name) { - for (var i = 0; i < cfg_names.length; ++i) - if (cfg_names[i] == name) - return i - return -1; - } - Component.onCompleted: { cfg_names = plasmoid.configuration.names.slice() cfg_colors = plasmoid.configuration.colors.slice() - cfg_guessed_max_values = plasmoid.configuration.guessed_max_values.slice() var tmp_last_filter = cfg_last_filter cfg_last_filter = "" for (var i in systemmonitor.sources) { - if (systemmonitor.sources[i].match(/[^\x{0000}-\x{007F}]/)) continue - var j = name_index(systemmonitor.sources[i]) + var name = systemmonitor.sources[i] + if (name.match(/[^\x{0000}-\x{007F}]/)) continue + var j = cfg_names.indexOf("sys." + name) if (j == -1) { sysmon_sources_model.append({ - "name": systemmonitor.sources[i], + "name": name, "color": plasmoid.configuration.default_color, "checked": false }); } else { sysmon_sources_model.append({ - "name": systemmonitor.sources[i], + "name": name, "color": cfg_colors[j], "checked": true }); diff --git a/plasmoid/contents/ui/main.qml b/plasmoid/contents/ui/main.qml index d983b27..714c52b 100644 --- a/plasmoid/contents/ui/main.qml +++ b/plasmoid/contents/ui/main.qml @@ -22,6 +22,8 @@ import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.components 2.0 as PlasmaComponents +import "../code/utils.js" as Utils + Item { id: main @@ -36,50 +38,121 @@ Item { connectedSources: ["org.kde.ksysguard.desktop"] } + // the data arrays + property var values: [] + property var orig_values: [] + + // execute source + PlasmaCore.DataSource { + id: execute_ds + engine: "executable" + + property var tick + + // what data is requested from the systemmonitor data source + connectedSources: { + var sources = [] + for (var i = 0; i < plasmoid.configuration.names.length; ++i) { + var exe_name = plasmoid.configuration.names[i] + if (exe_name.substring(0, 4) == "exe.") + sources.push(exe_name.substring(4)) + } + return sources + } + + // flush all values + onConnectedSourcesChanged: { + values = [] + orig_values = [] + plasmoid.configuration.guessed_max_value = 0.0 + } + + // called when new data is available + onNewData: { + var exe_source_name = "exe." + sourceName + for (var i = 0; i < plasmoid.configuration.names.length; ++i) { + if (plasmoid.configuration.names[i] == exe_source_name) { + while (i >= orig_values.length) orig_values.push(0) + orig_values[i] = Number(data.stdout) + while (i >= values.length) values.push(0) + values[i] = normalize(orig_values, data.stdout, i) + } + } + var current_tick = Math.floor(Date.now() / 1000) + if (tick != current_tick) { + valuesChanged() + orig_valuesChanged() + tick = current_tick + } + } + + // the update interval + interval: plasmoid.configuration.update_interval * 1000 + } + // the source of data about cpu PlasmaCore.DataSource { id: systemmonitor engine: "systemmonitor" - // the data arrays - property var values: [] - property var orig_values: [] - property var colors: [] + property var tick // what data is requested from the systemmonitor data source - connectedSources: plasmoid.configuration.names + connectedSources: { + var sources = [] + for (var i = 0; i < plasmoid.configuration.names.length; ++i) { + var sys_name = plasmoid.configuration.names[i] + if (sys_name.substring(0, 4) == "sys.") + sources.push(sys_name.substring(4)) + } + return sources + } + + // flush all values + onConnectedSourcesChanged: { + values = [] + orig_values = [] + plasmoid.configuration.guessed_max_value = 0.0 + } // called when new data is available onNewData: { + var sys_source_name = "sys." + sourceName for (var i = 0; i < plasmoid.configuration.names.length; ++i) { - if (plasmoid.configuration.names[i] == sourceName) { - while (i >= values.length) values.push(0) - values[i] = normalize(data.value, i) + if (plasmoid.configuration.names[i] == sys_source_name) { while (i >= orig_values.length) orig_values.push(0) orig_values[i] = Number(data.value) - while (i >= colors.length) colors.push(plasmoid.configuration.default_color) - colors[i] = plasmoid.configuration.colors[i] + while (i >= values.length) values.push(0) + values[i] = normalize(orig_values, data.value, i) } } - valuesChanged() - orig_valuesChanged() + var current_tick = Math.floor(Date.now() / 1000) + if (tick != current_tick) { + valuesChanged() + orig_valuesChanged() + tick = current_tick + } } // the update interval interval: plasmoid.configuration.update_interval * 1000 } - function normalize(value, i) { + function sum(values) { + var values_sum = 0 + for (var i = 0; i < values.length; ++i) { + values_sum += values[i] + } + return values_sum + } + + function normalize(orig_values, value, i) { var max_value = plasmoid.configuration.max_value if (max_value == 0.0) { - if (value > Number(plasmoid.configuration.guessed_max_values[i])) { - var new_guessed_max_values = plasmoid.configuration.guessed_max_values.slice() - new_guessed_max_values[i] = String(value) - plasmoid.configuration.guessed_max_values = new_guessed_max_values - } - for (var j = 0; j < plasmoid.configuration.guessed_max_values.length; ++j) - max_value += Number(plasmoid.configuration.guessed_max_values[j]) - max_value *= 1.01 + var values_sum = sum(orig_values) + if (values_sum > Number(plasmoid.configuration.guessed_max_value)) + plasmoid.configuration.guessed_max_value = values_sum + max_value = plasmoid.configuration.guessed_max_value * 1.2 } value = value / max_value return isNaN(value)? 0: Math.min(value, 1) @@ -108,13 +181,16 @@ Item { text: "" Connections { - target: systemmonitor + target: main onOrig_valuesChanged: { if (tooltip_main_item.visible) { var result = "" for (var i = 0; i < plasmoid.configuration.names.length; ++i) { if (i) result += "\n" - result += i18n("%1: %2", plasmoid.configuration.names[i], Math.round(systemmonitor.orig_values[i])) + var value = Utils.format_number(plasmoid.configuration, main.orig_values[i]) + var name = plasmoid.configuration.labels[i] + if (!name.length) name = plasmoid.configuration.names[i].substring(4) + result += i18n("%1: %2", name, value) } tooltip_text.text = result } @@ -128,38 +204,16 @@ Item { ColumnLayout { id: view - // tells the CircularMonitor to fill whole parent space + // tells the monitor to fill whole parent space anchors { fill: main } - CircularMonitor { - // hopefuly adjust label to center of circles - anchors { - topMargin: 5 - } - - // use configured colors - colors: systemmonitor.colors - // map the values to CircularMonitor values - values: systemmonitor.values - } - - // the label if requested - PlasmaComponents.Label { - id: label - - // use small caps for label - font.capitalization: Font.SmallCaps - - // tells the label to be centered in parent (in the centre of CircularMonitor) - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - - // the value - text: plasmoid.configuration.label + ConditionallyLoadedMonitor { + // map the values to monitor values + values: main.values + // map the original values to monitor values + orig_values: main.orig_values } } }