Web lists-archives.com

Re: plasma data engine / property loop




On Sunday 15 January 2017 11:16:22 Kevin Krammer wrote:
> Hi Martin,

Hi Kevin,

>
> On Sunday, 2017-01-15, 00:04:23, Martin Koller wrote:
> > Hi,
> >
> > trying to fix the systemload applet (and new to QML), how can one solve the
> > problem: - a data engine delivers the number of CPU cores
> > - depending on this number, I need to separately "connect" to additional
> > sources in this data engine
> >
> > This creates a property loop.
> > dataSources array depends on cores, but cores is set from dataSources
>
> How is cores set from dataSources?

As shown below via onNewData

> Does the source() function below write to cores?

no, it reads from it: for (var i = 0; i < cores; i++) ...

I'll just attach the real qml file
The message I see is
SystemLoadViewer.qml:123:5: QML : Binding loop detected for property "connectedSources"


>
> Cheers,
> Kevin
>
> > E.g. (pseudo code)
> >
> > property int cores: 0
> > dataSources: sources()
> >
> > function sources() { ... create array depending on property "cores", like
> > "cpu/cpu<core index>/nice" ... }
> >
> > onNewData: { cores = data.value }
>

--
Best regards/Schöne Grüße

Martin
A: Because it breaks the logical sequence of discussion
Q: Why is top posting bad?

()  ascii ribbon campaign - against html e-mail
/\                        - against proprietary attachments

Geschenkideen, Accessoires, Kulinarisches: www.lillehus.at
/*
 * Copyright (C) 2014 Martin Yrjölä <martin.yrjola@xxxxxxxxx>
 * Copyright (C) 2015 Joshua Worth <joshua@xxxxxxxxxxx>
 * Copyright (C) 2015 Kåre Särs <kae.sars@xxxxxx>
 *
 * 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
 * accepted by the membership of KDE e.V. (or its successor approved
 * by the membership of KDE e.V.), which shall act as a proxy
 * defined in Section 14 of version 3 of the license.
 *
 * 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 <http://www.gnu.org/licenses/>
 */

import QtQuick 2.2
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.plasma.extras 2.0 as PlasmaExtras
import org.kde.kio 1.0 as Kio
import org.kde.plasma.plasmoid 2.0

Item {
    id: main

    readonly property double maxCpuLoad: 100.0
    readonly property int borderWidth: 1
    readonly property int borderRounding: 3
    readonly property int headingLevel: 2

    property bool setColorsManually: plasmoid.configuration.setColorsManually

    property var cpuColors: setColorsManually ? [plasmoid.configuration.cpuSysColor,
                                                 plasmoid.configuration.cpuUserColor,
                                                 plasmoid.configuration.cpuNiceColor,
                                                 plasmoid.configuration.cpuIOWaitColor]
                                              : [theme.buttonFocusColor,
                                                 theme.highlightColor,
                                                 theme.visitedLinkColor,
                                                 theme.linkColor]

    property var memoryColors: setColorsManually ? [plasmoid.configuration.memApplicationColor,
                                                    plasmoid.configuration.memBuffersColor,
                                                    plasmoid.configuration.memCachedColor]
                                                 : [theme.buttonFocusColor,
                                                    theme.visitedLinkColor,
                                                    theme.highlightColor]

    property var swapColors: setColorsManually ? [plasmoid.configuration.swapUsedColor]
                                               : [theme.hightlightColor]

    // Make labels visible first time so that the
    // user knows which monitor is which.
    implicitWidth: widestLabelWidth()*1.3 * columnCount()
    implicitHeight: implicitWidth / 2

    property bool circularMonitorsInUse: plasmoid.configuration.monitorType == 1
    property bool compactBarMonitorsInUse: plasmoid.configuration.monitorType == 2
    property bool allCPUsShown: plasmoid.configuration.cpuAllActivated

    property double barsWidth: compactBarMonitorsInUse ? main.height * 0.35 * columnCount()
                                                       : main.height * 0.5 * columnCount()


    // Don't show icon in panel.
    Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation

    // Correct the size when in panel
    Layout.preferredWidth: {
        if (circularMonitorsInUse) {
            return parent.height * 1.2 * columnCount()
        }
        else if (!plasmoid.configuration.cpuAllActivated) {
            return barsWidth + rowLayout.spacing * (columnCount() - 1) // 0 * x == 0 (compact)
        }
        // else plasmoid.configuration.cpuAllActivated
        var wantedWidth = cpusRow.minWidth
        if (plasmoid.configuration.swapActivated) {
            wantedWidth += memColumn.minWidth
        }
        if (plasmoid.configuration.memoryActivated) {
            wantedWidth += swapColumn.minWidth
        }
        return wantedWidth
    }

    Layout.minimumWidth: {
        if (circularMonitorsInUse) {
            return units.gridUnit * columnCount() * 2
        }
        else if (!plasmoid.configuration.cpuAllActivated) {
            return memColumn.minWidth * columnCount() + rowLayout.spacing * (columnCount() - 1)
        }
        var wantedWidth = cpusRow.minWidth
        if (plasmoid.configuration.swapActivated) {
            wantedWidth += memColumn.minWidth
        }
        if (plasmoid.configuration.memoryActivated) {
            wantedWidth += swapColumn.minWidth
        }
        return wantedWidth
    }

    property bool labelsVisible

    Kio.KRun { id: kRun }

    // We need to get the full path to KSysguard to be able to run it
    PlasmaCore.DataSource {
        id: apps
        engine: "apps"
        connectedSources: ["org.kde.ksysguard.desktop"]
    }

    PlasmaCore.DataSource {
        id: dataSource
        engine: "systemmonitor"

        property string cpuSystem: "cpu/system/"
        property string niceLoad: cpuSystem + "nice"
        property string userLoad: cpuSystem + "user"
        property string sysLoad: cpuSystem + "sys"
        property string ioWait: cpuSystem + "wait"
        property string averageClock: cpuSystem + "AverageClock"
        property string totalLoad: cpuSystem + "TotalLoad"
        property string memPhysical: "mem/physical/"
        property string memFree: memPhysical + "free"
        property string memApplication: memPhysical + "application"
        property string memBuffers: memPhysical + "buf"
        property string memCached: memPhysical + "cached"
        property string memUsed: memPhysical + "used"
        property string swap: "mem/swap/"
        property string swapUsed: swap + "used"
        property string swapFree: swap + "free"
        property string cores: "system/cores"

        property var totalCpuLoadProportions: [.0, .0, .0, .0]
        property int maxCpuIndex: 0
        property var memoryUsageProportions: [.0, .0, .0]
        property double swapUsageProportion: .0

        connectedSources: sources()

        function sources() {
            var array = [niceLoad, userLoad, sysLoad,
                         ioWait, memFree, memApplication, memBuffers,
                         memCached, memUsed, swapUsed, swapFree,
                         averageClock, totalLoad, cores]

            if (plasmoid.configuration.cpuAllActivated) {
                for (var i = 0; i <= maxCpuIndex; i++) {
                    array.push("cpu/cpu" + i + "/TotalLoad");
                    array.push("cpu/cpu" + i + "/clock");
                    array.push("cpu/cpu" + i + "/nice");
                    array.push("cpu/cpu" + i + "/user");
                    array.push("cpu/cpu" + i + "/sys");
                    array.push("cpu/cpu" + i + "/wait");
                }
            }
            return array;
        }

        onNewData: {
            if (sourceName == sysLoad) {
                totalCpuLoadProportions[0] = fitCpuLoad(data.value)
            }
            else if (sourceName == userLoad) {
                totalCpuLoadProportions[1] = fitCpuLoad(data.value)
            }
            else if (sourceName == niceLoad) {
                totalCpuLoadProportions[2] = fitCpuLoad(data.value)
            }
            else if (sourceName == ioWait) {
                totalCpuLoadProportions[3] = fitCpuLoad(data.value)
                totalCpuLoadProportionsChanged()
            }
            else if (sourceName == memApplication) {
                memoryUsageProportions[0] = fitMemoryUsage(data.value)
            }
            else if (sourceName == memBuffers) {
                memoryUsageProportions[1] = fitMemoryUsage(data.value)
            }
            else if (sourceName == memCached) {
                memoryUsageProportions[2] = fitMemoryUsage(data.value)
                memoryUsageProportionsChanged()
            }
            else if (sourceName == swapUsed) {
                swapUsageProportion = fitSwapUsage(data.value)
                swapUsageProportionChanged()
            }
            else if (sourceName == cores) {
                maxCpuIndex = data.value - 1
            }
        }
        interval: 1000 * plasmoid.configuration.updateInterval
    }

    onWidthChanged: labelsVisible = shouldLabelsBeVisible()
    onAllCPUsShownChanged: labelsVisible = shouldLabelsBeVisible()

    function toolTipSubText() {
        var cpuLoadPart = "";
        var cpuClockPart = "";
        if (plasmoid.configuration.cpuAllActivated) {
            for (var i=0; i<�aSource.maxCpuIndex; i++) {
                if (i>0) {
                    cpuLoadPart += "\n"
                }
                var totalName = "cpu/cpu" + i + "/TotalLoad"
                var clockName = "cpu/cpu" + i + "/clock"
                var totValue = dataSource.data[totalName] ? dataSource.data[totalName].value : 0
                var clockValue = dataSource.data[clockName] ? dataSource.data[clockName].value : 0
                cpuLoadPart += i18n("CPU%1: %2% @ %3 Mhz", i,
                                    Math.round(totValue),
                                    Math.round(clockValue))
            }
        }
        else {
            var cpuLoad = dataSource.data[dataSource.totalLoad] ? dataSource.data[dataSource.totalLoad].value : 0
            var averageClock = dataSource.data[dataSource.averageClock] ? dataSource.data[dataSource.averageClock].value : 0
            cpuLoadPart = i18n("CPU: %1%", Math.round(cpuLoad))
            cpuClockPart = i18n("Average clock: %1 MHz", Math.round(averageClock))
        }
        var memFree = parseFloat(dataSource.data[dataSource.memFree] ? dataSource.data[dataSource.memFree].value : 0) / 1024
        var memUsed = parseFloat(dataSource.data[dataSource.memUsed] ? dataSource.data[dataSource.memUsed].value : 0) / 1024
        var memApplication = parseFloat(dataSource.data[dataSource.memApplication] ? dataSource.data[dataSource.memApplication].value : 0) / 1024
        var memTotal = memFree + memUsed
        var memoryPart = i18n("Memory: %1/%2 MiB", Math.round(memApplication), Math.round(memTotal))

        var swapFree = parseFloat(dataSource.data[dataSource.swapFree] ? dataSource.data[dataSource.swapFree].value : 0) / 1024
        var swapUsed = parseFloat(dataSource.data[dataSource.swapUsed] ? dataSource.data[dataSource.swapUsed].value : 0) / 1024
        var swapTotal = swapFree + swapUsed
        var swapPart = i18n("Swap: %1/%2 MiB", Math.round(swapUsed), Math.round(swapTotal))

        if (cpuClockPart === "") {
            return [cpuLoadPart, memoryPart, swapPart].join("\n")
        }

        return [cpuLoadPart, cpuClockPart, memoryPart, swapPart].join("\n")
    }

    function fitCpuLoad(load) {
        var x = load / maxCpuLoad;
        if (isNaN(x)) {return 0;}
        return Math.min(x, 1); // Ensure that we do not get values that might cause problems
    }

    function fitMemoryUsage(usage) {
        if (!dataSource.data[dataSource.memFree] || !dataSource.data[dataSource.memUsed])
            return 0;

        var x = (usage / (parseFloat(dataSource.data[dataSource.memFree].value) +
                         parseFloat(dataSource.data[dataSource.memUsed].value)))
        if (isNaN(x)) {return 0;}
        return Math.min(x, 1);
    }

    function fitSwapUsage(usage) {
        if (!dataSource.data[dataSource.swapFree])
            return 0;

        var x = (usage / (parseFloat(usage) + parseFloat(dataSource.data[dataSource.swapFree].value)))

        if (isNaN(x)) {return 0;}
        return Math.min(x, 1);
    }

    function columnCount() {
        var columns = 0;
        var activeMonitors = [plasmoid.configuration.cpuActivated,
            plasmoid.configuration.memoryActivated,
            plasmoid.configuration.swapActivated]

        for (var i = 0; i < activeMonitors.length; i++) {
            if (activeMonitors[i]) {
                columns++;
            }
        }
        return columns
    }

    function columnWidth(compact) {
        var columns = columnCount();
        var width = rowLayout.width / columns;
        if (!compact) {
            width -= rowLayout.spacing * (columns - 1);
        }
        return width;
    }

    function widestLabelWidth() {
        var widest = 0;
        if (plasmoid.configuration.cpuActivated) {
            widest = cpuLabel.paintedWidth
        }
        if (plasmoid.configuration.memoryActivated) {
            widest = Math.max(widest, memoryLabel.paintedWidth)
        }
        if (plasmoid.configuration.swapActivated) {
            widest = Math.max(widest, swapLabel.paintedWidth)
        }
        return widest
    }

    // Hide all labels when one of them is wider than the column width
    function shouldLabelsBeVisible() {
        if (plasmoid.configuration.cpuAllActivated) {
            return false;
        }
        return widestLabelWidth() <= columnWidth()
    }

    PlasmaCore.ToolTipArea {
        id: stdToolTip
        anchors.fill: parent
        active: true
        mainText: i18n("System load")
        subText: toolTipSubText()
        visible: !plasmoid.configuration.cpuAllActivated || dataSource.maxCpuIndex < 5

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                kRun.openUrl(apps.data["org.kde.ksysguard.desktop"].entryPath)
            }
        }
    }

    PlasmaCore.ToolTipArea {
        anchors.fill: parent
        active: true
        visible: !stdToolTip.visible

        mainItem: Item {
            height: childrenRect.height + units.gridUnit * 2
            width: childrenRect.width + units.gridUnit * 2
            ColumnLayout {
                anchors {
                    top: parent.top
                    left:parent.left
                    margins: units.gridUnit
                }
                PlasmaExtras.Heading {
                    id: tooltipMaintext
                    level: 3
                    text: stdToolTip.mainText
                }
                PlasmaComponents.Label {
                    id: tooltipSubtext
                    text: toolTipSubText()
                    opacity: 0.7
                }
            }
        }

        MouseArea {
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                kRun.openUrl(apps.data["org.kde.ksysguard.desktop"].entryPath)
            }
        }
    }

    RowLayout {
        id: rowLayout

        anchors {
            fill: main
        }

        spacing: main.compactBarMonitorsInUse ? 0 : 5


        RowLayout {
            id: cpusRow
            property int minCpuWidth: memColumn.minWidth * 0.33
            property int minWidth : Math.max(memColumn.minWidth * 2, cpuRepeater.count * minCpuWidth)
            visible: plasmoid.configuration.cpuActivated && plasmoid.configuration.cpuAllActivated
            Layout.minimumWidth: minWidth
            Layout.preferredWidth: height * 2

            spacing: 0
            Repeater {
                id: cpuRepeater
                model: (dataSource.maxCpuIndex+1)

                delegate: ColumnLayout {
                    Layout.minimumWidth: cpusRow.minCpuWidth
                    property int cpuIndex: index

                    PlasmaExtras.Heading {
                        id: cpuLabel
                        level: main.headingLevel
                        text: i18n("CPU %1", cpuIndex)
                        visible: main.labelsVisible
                    }
                    ConditionallyLoadedMonitors {
                        colors: cpuColors
                        property string niceLoad: "cpu/cpu" + cpuIndex + "/nice"
                        property string userLoad: "cpu/cpu" + cpuIndex + "/user"
                        property string sysLoad:  "cpu/cpu" + cpuIndex + "/sys"
                        property string ioWait:   "cpu/cpu" + cpuIndex + "/wait"
                        property var cpuLoadProportions: dataSource.data[ioWait] ? [
                        fitCpuLoad(dataSource.data[sysLoad].value),
                        fitCpuLoad(dataSource.data[userLoad].value),
                        fitCpuLoad(dataSource.data[niceLoad].value),
                        fitCpuLoad(dataSource.data[ioWait].value)
                        ] : [.0, .0, .0, .0]
                        proportions: cpuLoadProportions
                    }
                }
            }
        }

        ColumnLayout {
            id: cpuColumn
            property double minWidth: memColumn.minWidth
            visible: plasmoid.configuration.cpuActivated && !plasmoid.configuration.cpuAllActivated
            Layout.minimumWidth: minWidth
            Layout.preferredWidth: height

            PlasmaExtras.Heading {
                id: cpuLabel
                level: main.headingLevel
                text: i18n("CPU")
                visible: main.labelsVisible
            }

            ConditionallyLoadedMonitors {
                colors: cpuColors
                proportions: dataSource.totalCpuLoadProportions
            }
        }

        ColumnLayout {
            id: memColumn
            property double minWidth: units.gridUnit * 0.7
            visible: plasmoid.configuration.memoryActivated
            Layout.minimumWidth: minWidth
            Layout.preferredWidth: height

            PlasmaExtras.Heading {
                id: memoryLabel
                level: main.headingLevel
                text: i18n("Memory")
                visible: main.labelsVisible
            }

            ConditionallyLoadedMonitors {
                colors: memoryColors
                proportions: dataSource.memoryUsageProportions
            }
        }

        ColumnLayout {
            id: swapColumn
            property double minWidth: memColumn.minWidth
            visible: plasmoid.configuration.swapActivated
            Layout.minimumWidth: minWidth
            Layout.preferredWidth: height

            PlasmaExtras.Heading {
                id: swapLabel
                level: main.headingLevel
                text: i18n("Swap")
                visible: main.labelsVisible
            }

            ConditionallyLoadedMonitors {
                colors: swapColors
                proportions: [dataSource.swapUsageProportion]
            }
        }
    } // rowLayout
} // main

Attachment: signature.asc
Description: This is a digitally signed message part.