Paste P469

Masterwork From Distant Lands
ActivePublic

Authored by davidedmundson on Sep 18 2019, 12:29 PM.
commit 9c18850f199f691258ccc5c37bdcb63c02ea7021
Author: David Edmundson <kde@davidedmundson.co.uk>
Date: Thu Aug 22 11:45:55 2019 +0100
Create a plugin framework for processes
Summary:
Currently everything for processes is hardcoded with a method for each
process property. This is core functionality like CPU usage and memory
usage but it's not very extensible.
Currently ProcessModel is full of extra hacks to add X11 data when
really it should be a dumb proxier of information.
We have a pending patch to show network stats, and we have a pending
patch to add powertop information, which all work in a different way
from just reading data in /proc
In order to keep it flexible a more generic format method is added which
doesn't require hardcoding knowledge of types.
This patch is part of a series, next steps are adding various plugins,
stripping proces model - and then using the ProcessAttribute class to
provide the metadata for the core process attributes so that
ProcessModel can become a very simple view with no code duplication.
Reviewers: #plasma, ahiemstra
Subscribers: ahiemstra, alexde, broulik, plasma-devel
Tags: #plasma
Differential Revision: https://phabricator.kde.org/D23287
diff --git a/processcore/CMakeLists.txt b/processcore/CMakeLists.txt
index e92fd50..0b6d4e0 100644
--- a/processcore/CMakeLists.txt
+++ b/processcore/CMakeLists.txt
@@ -3,16 +3,20 @@ add_definitions(-DTRANSLATION_DOMAIN=\"processcore\")
########### next target ###############
set(ksysguard_LIB_SRCS
+ extended_process_list.cpp
+ formatter.cpp
processes.cpp
process.cpp
+ process_attribute.cpp
processes_local_p.cpp
processes_remote_p.cpp
processes_base_p.cpp
processes_atop_p.cpp
+ process_data_provider.cpp
+ unit.cpp
)
ecm_qt_declare_logging_category(ksysguard_LIB_SRCS HEADER processcore_debug.h IDENTIFIER LIBKSYSGUARD_PROCESSCORE CATEGORY_NAME org.kde.libksysguard.processcore)
-
add_library(processcore ${ksysguard_LIB_SRCS})
add_library(KF5::ProcessCore ALIAS processcore)
@@ -21,6 +25,7 @@ target_link_libraries(processcore
Qt5::Core
PRIVATE
KF5::I18n
+ KF5::CoreAddons
${ZLIB_LIBRARIES}
)
@@ -42,6 +47,10 @@ install(TARGETS processcore EXPORT libksysguardLibraryTargets ${KDE_INSTALL_TARG
install( FILES
processes.h
process.h
+ process_attribute.h
+ process_data_provider.h
+ formatter.h
+ unit.h
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/ksysguard/processcore
COMPONENT Devel
)
diff --git a/processcore/extended_process_list.cpp b/processcore/extended_process_list.cpp
new file mode 100644
index 0000000..4a1d000
--- /dev/null
+++ b/processcore/extended_process_list.cpp
@@ -0,0 +1,100 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "extended_process_list.h"
+
+#include <KPluginLoader>
+#include <KPluginFactory>
+#include <KPluginMetaData>
+
+#include "process_data_provider.h"
+#include "process_attribute.h"
+#include "processcore_debug.h"
+
+using namespace KSysGuard;
+
+class ExtendedProcesses::Private
+{
+public:
+ Private(ExtendedProcesses *q);
+ void loadPlugins();
+
+ ExtendedProcesses *q;
+ QVector<ProcessDataProvider *> m_providers;
+};
+
+ExtendedProcesses::Private::Private(ExtendedProcesses *_q)
+ :q(_q)
+{}
+
+ExtendedProcesses::ExtendedProcesses(QObject *parent):
+ Processes(QString(), parent),
+ d(new Private(this))
+{
+ d->loadPlugins();
+
+ connect(this, &KSysGuard::Processes::beginRemoveProcess, this, [this](KSysGuard::Process *process) {
+ const auto attrs = attributes();
+ for (auto a: attrs) {
+ a->clearData(process);
+ }
+ });
+
+ connect(this, &KSysGuard::Processes::updated, this, [this]() {
+ for (auto p: qAsConst(d->m_providers)) {
+ if (p->enabled()) {
+ p->update();
+ }
+ }
+ });
+}
+
+ExtendedProcesses::~ExtendedProcesses()
+{
+}
+
+QVector<ProcessAttribute *> ExtendedProcesses::attributes() const
+{
+ QVector<ProcessAttribute *> rc;
+ for (auto p: qAsConst(d->m_providers)) {
+ rc << p->attributes();
+ }
+ return rc;
+}
+
+void ExtendedProcesses::Private::loadPlugins()
+{
+ //instantiate all plugins
+ const QVector<KPluginMetaData> listMetaData = KPluginLoader::findPlugins(QStringLiteral("ksysguard/process"));
+ for (const auto &pluginMetaData: listMetaData) {
+ qCDebug(LIBKSYSGUARD_PROCESSCORE) << "loading plugin" << pluginMetaData.name();
+ auto factory = qobject_cast<KPluginFactory*>(pluginMetaData.instantiate());
+ if (!factory) {
+ qCCritical(LIBKSYSGUARD_PROCESSCORE) << "failed to load plugin factory" << pluginMetaData.name();
+ continue;
+ }
+ ProcessDataProvider *provider = factory->create<ProcessDataProvider>(q);
+ if (!provider) {
+ qCCritical(LIBKSYSGUARD_PROCESSCORE) << "failed to instantiate ProcessDataProvider" << pluginMetaData.name();
+ continue;
+ }
+ m_providers << provider;
+ }
+}
+
+
diff --git a/processcore/extended_process_list.h b/processcore/extended_process_list.h
new file mode 100644
index 0000000..c740edc
--- /dev/null
+++ b/processcore/extended_process_list.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#pragma once
+
+#include <processcore/processes.h>
+
+#include <QObject>
+
+namespace KSysGuard {
+class ProcessAttribute;
+
+class Q_DECL_EXPORT ExtendedProcesses : public KSysGuard::Processes
+{
+ Q_OBJECT
+public:
+ ExtendedProcesses(QObject *parent = nullptr);
+ ~ExtendedProcesses() override;
+
+ QVector<ProcessAttribute *> attributes() const;
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+}
diff --git a/processcore/formatter.cpp b/processcore/formatter.cpp
new file mode 100644
index 0000000..4138498
--- /dev/null
+++ b/processcore/formatter.cpp
@@ -0,0 +1,435 @@
+/*
+ Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
+
+ formatBootTimestamp is based on TimeUtil class:
+ Copyright (C) 2014 Gregor Mi <codestruct@posteo.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "formatter.h"
+
+#include <KLocalizedString>
+
+#include <QLocale>
+#include <QTime>
+
+#include <cmath>
+
+#ifdef Q_OS_OSX
+#include <mach/clock.h>
+#include <mach/mach.h>
+#else
+#include <ctime>
+#endif
+
+#include <unistd.h>
+
+namespace KSysGuard
+{
+
+// TODO: Is there a bit nicer way to handle formatting?
+
+static KLocalizedString unitFormat(Unit unit)
+{
+ const static KLocalizedString B = ki18nc("Bytes unit symbol", "%1 B");
+ const static KLocalizedString KiB = ki18nc("Kilobytes unit symbol", "%1 KiB");
+ const static KLocalizedString MiB = ki18nc("Megabytes unit symbol", "%1 MiB");
+ const static KLocalizedString GiB = ki18nc("Gigabytes unit symbol", "%1 GiB");
+ const static KLocalizedString TiB = ki18nc("Terabytes unit symbol", "%1 TiB");
+ const static KLocalizedString PiB = ki18nc("Petabytes unit symbol", "%1 PiB");
+
+ const static KLocalizedString bps = ki18nc("Bytes per second unit symbol", "%1 B/s");
+ const static KLocalizedString Kbps = ki18nc("Kilobytes per second unit symbol", "%1 KiB/s");
+ const static KLocalizedString Mbps = ki18nc("Megabytes per second unit symbol", "%1 MiB/s");
+ const static KLocalizedString Gbps = ki18nc("Gigabytes per second unit symbol", "%1 GiB/s");
+ const static KLocalizedString Tbps = ki18nc("Gigabytes per second unit symbol", "%1 TiB/s");
+ const static KLocalizedString Pbps = ki18nc("Gigabytes per second unit symbol", "%1 PiB/s");
+
+ const static KLocalizedString Hz = ki18nc("Hertz unit symbol", "%1 Hz");
+ const static KLocalizedString kHz = ki18nc("Kilohertz unit symbol", "%1 kHz");
+ const static KLocalizedString MHz = ki18nc("Megahertz unit symbol", "%1 MHz");
+ const static KLocalizedString GHz = ki18nc("Gigahertz unit symbol", "%1 GHz");
+ const static KLocalizedString THz = ki18nc("Terahertz unit symbol", "%1 THz");
+ const static KLocalizedString PHz = ki18nc("Petahertz unit symbol", "%1 PHz");
+
+ const static KLocalizedString percent = ki18nc("Percent unit", "%1%");
+ const static KLocalizedString RPM = ki18nc("Revolutions per minute unit symbol", "%1 RPM");
+ const static KLocalizedString C = ki18nc("Celsius unit symbol", "%1°C");
+ const static KLocalizedString dBm = ki18nc("Decibels unit symbol", "%1 dBm");
+ const static KLocalizedString s = ki18nc("Seconds unit symbol", "%1s");
+ const static KLocalizedString V = ki18nc("Volts unit symbol", "%1 V");
+ const static KLocalizedString W = ki18nc("Watts unit symbol", "%1 W");
+ const static KLocalizedString rate = ki18nc("Rate unit symbol", "%1 s⁻¹");
+ const static KLocalizedString unitless = ki18nc("Unitless", "%1");
+
+ switch (unit) {
+ case UnitByte:
+ return B;
+ case UnitKiloByte:
+ return KiB;
+ case UnitMegaByte:
+ return MiB;
+ case UnitGigaByte:
+ return GiB;
+ case UnitTeraByte:
+ return TiB;
+ case UnitPetaByte:
+ return PiB;
+
+ case UnitByteRate:
+ return bps;
+ case UnitKiloByteRate:
+ return Kbps;
+ case UnitMegaByteRate:
+ return Mbps;
+ case UnitGigaByteRate:
+ return Gbps;
+ case UnitTeraByteRate:
+ return Tbps;
+ case UnitPetaByteRate:
+ return Pbps;
+
+ case UnitHertz:
+ return Hz;
+ case UnitKiloHertz:
+ return kHz;
+ case UnitMegaHertz:
+ return MHz;
+ case UnitGigaHertz:
+ return GHz;
+ case UnitTeraHertz:
+ return THz;
+ case UnitPetaHertz:
+ return PHz;
+
+ case UnitCelsius:
+ return C;
+ case UnitDecibelMilliWatts:
+ return dBm;
+ case UnitPercent:
+ return percent;
+ case UnitRate:
+ return rate;
+ case UnitRpm:
+ return RPM;
+ case UnitSecond:
+ return s;
+ case UnitVolt:
+ return V;
+ case UnitWatt:
+ return W;
+
+ default:
+ return unitless;
+ }
+}
+
+static int unitOrder(Unit unit)
+{
+ switch (unit) {
+ case UnitByte:
+ case UnitKiloByte:
+ case UnitMegaByte:
+ case UnitGigaByte:
+ case UnitTeraByte:
+ case UnitPetaByte:
+ case UnitByteRate:
+ case UnitKiloByteRate:
+ case UnitMegaByteRate:
+ case UnitGigaByteRate:
+ case UnitTeraByteRate:
+ case UnitPetaByteRate:
+ return 1024;
+
+ case UnitHertz:
+ case UnitKiloHertz:
+ case UnitMegaHertz:
+ case UnitGigaHertz:
+ case UnitTeraHertz:
+ case UnitPetaHertz:
+ return 1000;
+
+ default:
+ return 0;
+ }
+}
+
+static Unit unitBase(Unit unit)
+{
+ switch (unit) {
+ case UnitByte:
+ case UnitKiloByte:
+ case UnitMegaByte:
+ case UnitGigaByte:
+ case UnitTeraByte:
+ case UnitPetaByte:
+ return UnitByte;
+
+ case UnitByteRate:
+ case UnitKiloByteRate:
+ case UnitMegaByteRate:
+ case UnitGigaByteRate:
+ case UnitTeraByteRate:
+ case UnitPetaByteRate:
+ return UnitByteRate;
+
+ case UnitHertz:
+ case UnitKiloHertz:
+ case UnitMegaHertz:
+ case UnitGigaHertz:
+ case UnitTeraHertz:
+ case UnitPetaHertz:
+ return UnitHertz;
+
+ default:
+ return unit;
+ }
+}
+
+static Unit adjustedUnit(qreal value, Unit unit, MetricPrefix prefix)
+{
+ const int order = unitOrder(unit);
+ if (!order) {
+ return unit;
+ }
+
+ const Unit baseUnit = unitBase(unit);
+ const MetricPrefix basePrefix = MetricPrefix(unit - baseUnit);
+
+ if (prefix == MetricPrefixAutoAdjust) {
+ const qreal absoluteValue = value * std::pow(order, int(basePrefix));
+ if (absoluteValue > 0) {
+ const int targetPrefix = std::log2(absoluteValue) / std::log2(order);
+ if (targetPrefix <= MetricPrefixLast) {
+ prefix = MetricPrefix(targetPrefix);
+ }
+ }
+ if (prefix == MetricPrefixAutoAdjust) {
+ prefix = basePrefix;
+ }
+ }
+
+ return Unit(prefix + baseUnit);
+}
+
+static QString formatNumber(const QVariant &value, Unit unit, MetricPrefix prefix, FormatOptions options)
+{
+ qreal amount = value.toDouble();
+
+ if (!options.testFlag(FormatOptionShowNull) && qFuzzyIsNull(amount)) {
+ return QString();
+ }
+
+ const Unit adjusted = adjustedUnit(amount, unit, prefix);
+ if (adjusted != unit) {
+ amount /= std::pow(unitOrder(unit), adjusted - unit);
+ }
+
+ const int precision = (value.type() != QVariant::Double && adjusted <= unit) ? 0 : 1;
+ const QString text = QLocale().toString(amount, 'f', precision);
+
+ return unitFormat(adjusted).subs(text).toString();
+}
+
+static QString formatTime(const QVariant &value)
+{
+ const qlonglong seconds = value.toLongLong();
+
+ const QString minutesString = QString::number(seconds / 60);
+ const QString secondsScring = QStringLiteral("%1").arg(seconds % 60, 2, 10, QLatin1Char('0'));
+
+ return minutesString + QLatin1Char(':') + secondsScring;
+}
+
+static QString formatBootTimestamp(const QVariant &value, FormatOptions options)
+{
+ const qlonglong clockTicksSinceSystemBoot = value.toLongLong();
+ const QDateTime now = QDateTime::currentDateTime();
+
+#ifdef Q_OS_OSX
+ clock_serv_t cclock;
+ mach_timespec_t tp;
+
+ host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+ clock_get_time(cclock, &tp);
+ mach_port_deallocate(mach_task_self(), cclock);
+#else
+ timespec tp;
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+#endif
+ const QDateTime systemBootTime = now.addSecs(-tp.tv_sec);
+
+ const long clockTicksPerSecond = sysconf(_SC_CLK_TCK);
+ const qreal secondsSinceSystemBoot = qreal(clockTicksSinceSystemBoot) / clockTicksPerSecond;
+ const QDateTime absoluteStartTime = systemBootTime.addSecs(secondsSinceSystemBoot);
+
+ if (!options.testFlag(FormatOptionAgo)) {
+ return QLocale().toString(absoluteStartTime);
+ }
+
+ const qint64 totalSeconds = absoluteStartTime.secsTo(now);
+ const qint64 totalMinutes = totalSeconds / 60.0;
+ const qint64 totalHours = totalSeconds / 60.0 / 60.0;
+ const qint64 totalDays = totalSeconds / 60.0 / 60.0 / 24.0;
+
+ if (!totalMinutes) {
+ return i18nc("contains a abbreviated time unit: (s)econds", "%1s ago", totalSeconds);
+ }
+
+ if (!totalHours) {
+ const int seconds = totalSeconds - totalMinutes * 60;
+ return i18nc("contains abbreviated time units: (m)inutes and (s)econds", "%1m %2s ago",
+ totalMinutes, seconds);
+ }
+
+ if (!totalDays) {
+ const int seconds = totalSeconds - totalMinutes * 60;
+ const int minutes = totalMinutes - totalHours * 60;
+ return i18nc("contains abbreviated time units: (h)ours, (m)inutes and (s)econds)",
+ "%1h %2m %3s ago", totalHours, minutes, seconds);
+ }
+
+ const int minutes = totalMinutes - totalHours * 60;
+ const int hours = totalHours - totalDays * 24;
+ return i18ncp("contains also abbreviated time units: (h)ours and (m)inutes",
+ "%1 day %2h %3m ago", "%1 days %2h %3m ago", totalDays, hours, minutes);
+}
+
+qreal Formatter::scaleDownFactor(const QVariant &value, Unit unit, MetricPrefix targetPrefix)
+{
+ const Unit adjusted = adjustedUnit(value.toDouble(), unit, targetPrefix);
+ if (adjusted == unit) {
+ return 1;
+ }
+
+ return std::pow(unitOrder(unit), adjusted - unit);
+}
+
+KLocalizedString Formatter::localizedString(const QVariant &value, Unit unit, MetricPrefix targetPrefix)
+{
+ const Unit adjusted = adjustedUnit(value.toDouble(), unit, targetPrefix);
+ return unitFormat(adjusted);
+}
+
+QString Formatter::formatValue(const QVariant &value, Unit unit, MetricPrefix targetPrefix, FormatOptions options)
+{
+ switch (unit) {
+ case UnitByte:
+ case UnitKiloByte:
+ case UnitMegaByte:
+ case UnitGigaByte:
+ case UnitTeraByte:
+ case UnitPetaByte:
+ case UnitByteRate:
+ case UnitKiloByteRate:
+ case UnitMegaByteRate:
+ case UnitGigaByteRate:
+ case UnitTeraByteRate:
+ case UnitPetaByteRate:
+ case UnitHertz:
+ case UnitKiloHertz:
+ case UnitMegaHertz:
+ case UnitGigaHertz:
+ case UnitTeraHertz:
+ case UnitPetaHertz:
+ case UnitPercent:
+ case UnitRate:
+ case UnitRpm:
+ case UnitCelsius:
+ case UnitDecibelMilliWatts:
+ case UnitVolt:
+ case UnitWatt:
+ case UnitSecond:
+ return formatNumber(value, unit, targetPrefix, options);
+
+ case UnitBootTimestamp:
+ return formatBootTimestamp(value, options);
+ case UnitTime:
+ return formatTime(value);
+
+ default:
+ return value.toString();
+ }
+}
+
+QString Formatter::symbol(Unit unit)
+{
+ // TODO: Is it possible to avoid duplication of these symbols?
+ switch (unit) {
+ case UnitByte:
+ return i18nc("Bytes unit symbol", "B");
+ case UnitKiloByte:
+ return i18nc("Kilobytes unit symbol", "KiB");
+ case UnitMegaByte:
+ return i18nc("Megabytes unit symbol", "MiB");
+ case UnitGigaByte:
+ return i18nc("Gigabytes unit symbol", "GiB");
+ case UnitTeraByte:
+ return i18nc("Terabytes unit symbol", "TiB");
+ case UnitPetaByte:
+ return i18nc("Petabytes unit symbol", "PiB");
+
+ case UnitByteRate:
+ return i18nc("Bytes per second unit symbol", "B/s");
+ case UnitKiloByteRate:
+ return i18nc("Kilobytes per second unit symbol", "KiB/s");
+ case UnitMegaByteRate:
+ return i18nc("Megabytes per second unit symbol", "MiB/s");
+ case UnitGigaByteRate:
+ return i18nc("Gigabytes per second unit symbol", "GiB/s");
+ case UnitTeraByteRate:
+ return i18nc("Gigabytes per second unit symbol", "TiB/s");
+ case UnitPetaByteRate:
+ return i18nc("Gigabytes per second unit symbol", "PiB/s");
+
+ case UnitHertz:
+ return i18nc("Hertz unit symbol", "Hz");
+ case UnitKiloHertz:
+ return i18nc("Kilohertz unit symbol", "kHz");
+ case UnitMegaHertz:
+ return i18nc("Megahertz unit symbol", "MHz");
+ case UnitGigaHertz:
+ return i18nc("Gigahertz unit symbol", "GHz");
+ case UnitTeraHertz:
+ return i18nc("Terahertz unit symbol", "THz");
+ case UnitPetaHertz:
+ return i18nc("Petahertz unit symbol", "PHz");
+
+ case UnitPercent:
+ return i18nc("Percent unit", "%");
+ case UnitRpm:
+ return i18nc("Revolutions per minute unit symbol", "RPM");
+ case UnitCelsius:
+ return i18nc("Celsius unit symbol", "°C");
+ case UnitDecibelMilliWatts:
+ return i18nc("Decibels unit symbol", "dBm");
+ case UnitSecond:
+ return i18nc("Seconds unit symbol", "s");
+ case UnitVolt:
+ return i18nc("Volts unit symbol", "V");
+ case UnitWatt:
+ return i18nc("Watts unit symbol", "W");
+ case UnitRate:
+ return i18nc("Rate unit symbol", "s⁻¹");
+
+ default:
+ return QString();
+ }
+}
+
+} // namespace KSysGuard
diff --git a/processcore/formatter.h b/processcore/formatter.h
new file mode 100644
index 0000000..cbecd87
--- /dev/null
+++ b/processcore/formatter.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+// Own
+#include "unit.h"
+
+// Qt
+#include <QString>
+#include <QVariant>
+
+class KLocalizedString;
+
+namespace KSysGuard
+{
+
+/**
+ * This enum type is used to specify format options.
+ */
+enum FormatOption {
+ FormatOptionNone = 0,
+ FormatOptionAgo = 1 << 0,
+ FormatOptionShowNull = 1 << 1,
+};
+Q_DECLARE_FLAGS(FormatOptions, FormatOption)
+
+class Q_DECL_EXPORT Formatter
+{
+public:
+ /**
+ * Returns the scale factor suitable for display.
+ *
+ * @param value The maximium output value.
+ * @param unit The unit of the value.
+ * @param targetPrefix Preferred metric prefix.
+ */
+ static qreal scaleDownFactor(const QVariant &value, Unit unit,
+ MetricPrefix targetPrefix = MetricPrefixAutoAdjust);
+
+ /**
+ * Returns localized string that is suitable for display.
+ *
+ * @param value The maximum output value.
+ * @param unit The unit of the value.
+ * @param targetPrefix Preferred metric prefix.
+ */
+ static KLocalizedString localizedString(const QVariant &value, Unit unit,
+ MetricPrefix targetPrefix = MetricPrefixAutoAdjust);
+
+ /**
+ * Converts @p value to the appropriate displayable string.
+ *
+ * The returned string is localized.
+ *
+ * @param value The value to be converted.
+ * @param unit The unit of the value.
+ * @param targetPrefix Preferred metric prefix.
+ * @param options
+ */
+ static QString formatValue(const QVariant &value, Unit unit,
+ MetricPrefix targetPrefix = MetricPrefixAutoAdjust,
+ FormatOptions options = FormatOptionNone);
+
+ /**
+ * Returns a symbol that corresponds to the given @p unit.
+ *
+ * The returned unit symbol is localized.
+ */
+ static QString symbol(Unit unit);
+};
+
+} // namespace KSysGuard
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(KSysGuard::FormatOptions)
diff --git a/processcore/process_attribute.cpp b/processcore/process_attribute.cpp
new file mode 100644
index 0000000..6aefff3
--- /dev/null
+++ b/processcore/process_attribute.cpp
@@ -0,0 +1,151 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "process_attribute.h"
+#include "processes.h"
+
+using namespace KSysGuard;
+
+class KSysGuard::ProcessAttribute::Private
+{
+public:
+ QString m_id;
+
+ QString m_name;
+ QString m_shortName;
+ QString m_description;
+ qreal m_min = 0;
+ qreal m_max = 0;
+ KSysGuard::Unit m_unit = KSysGuard::UnitInvalid; //Both a format hint and implies data type (i.e double/string)
+
+ QHash<KSysGuard::Process *, QVariant> m_data;
+ bool m_enabled = false;
+};
+
+ProcessAttribute::ProcessAttribute(const QString &id, QObject *parent)
+ : ProcessAttribute(id, QString(), parent)
+{}
+
+ProcessAttribute::ProcessAttribute(const QString &id, const QString &name, QObject *parent)
+ : QObject(parent),
+ d(new Private)
+{
+ d->m_id = id;
+ d->m_name = name;
+}
+
+ProcessAttribute::~ProcessAttribute()
+{
+}
+
+QString ProcessAttribute::id() const
+{
+ return d->m_id;
+}
+
+bool ProcessAttribute::enabled() const
+{
+ return d->m_enabled;
+}
+
+void ProcessAttribute::setEnabled(const bool enabled)
+{
+ if (d->m_enabled == enabled) {
+ return;
+ }
+ d->m_enabled = enabled;
+ emit enabledChanged(enabled);
+}
+
+QString ProcessAttribute::name() const
+{
+ return d->m_name;
+}
+
+void ProcessAttribute::setName(const QString &name)
+{
+ d->m_name = name;
+}
+
+QString ProcessAttribute::shortName() const
+{
+ return d->m_shortName.isEmpty() ? d->m_name : d->m_shortName;
+}
+
+void ProcessAttribute::setShortName(const QString &name)
+{
+ d->m_shortName = name;
+}
+
+QString ProcessAttribute::description() const
+{
+ return d->m_description;
+}
+
+void ProcessAttribute::setDescription(const QString &description)
+{
+ d->m_description = description;
+}
+
+qreal ProcessAttribute::min() const
+{
+ return d->m_min;
+}
+
+void ProcessAttribute::setMin(const qreal min)
+{
+ d->m_min = min;
+}
+
+qreal ProcessAttribute::max() const
+{
+ return d->m_max;
+}
+
+void ProcessAttribute::setMax(const qreal max)
+{
+ d->m_max = max;
+}
+
+KSysGuard::Unit ProcessAttribute::unit() const
+{
+ return d->m_unit;
+}
+
+void ProcessAttribute::setUnit(KSysGuard::Unit unit)
+{
+ d->m_unit = unit;
+}
+
+QVariant ProcessAttribute::data(KSysGuard::Process *process)
+{
+ return d->m_data.value(process);
+}
+
+void ProcessAttribute::setData(KSysGuard::Process *process, const QVariant &value)
+{
+ d->m_data[process] = value;
+ emit dataChanged(process);
+}
+
+void ProcessAttribute::clearData(KSysGuard::Process *process)
+{
+ d->m_data.remove(process);
+ emit dataChanged(process);
+}
diff --git a/processcore/process_attribute.h b/processcore/process_attribute.h
new file mode 100644
index 0000000..af3b2c2
--- /dev/null
+++ b/processcore/process_attribute.h
@@ -0,0 +1,112 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#pragma once
+
+#include <QObject>
+#include <QVariant>
+
+#include "unit.h"
+
+namespace KSysGuard {
+
+class Process;
+
+class Q_DECL_EXPORT ProcessAttribute : public QObject
+{
+ Q_OBJECT
+public:
+ ProcessAttribute(const QString &id, QObject *parent);
+ ProcessAttribute(const QString &id, const QString &name, QObject *parent);
+
+ ~ProcessAttribute() override;
+
+ /**
+ * A unique non-translatable ID for this attribute. For saving in config files
+ */
+ QString id() const;
+
+ /**
+ * Controls whether we should fetch process attributes
+ */
+ bool enabled() const;
+ void setEnabled(const bool enable);
+
+ /**
+ * A translated user facing name for the attribute.
+ * e.g "Download Speed"
+ */
+ QString name() const;
+ void setName(const QString &name);
+
+ /**
+ * A translated shorter version of the name
+ * for use in table column headers for example
+ * e.g "D/L"
+ * If unset, name is returned
+ */
+ QString shortName() const;
+ void setShortName(const QString &name);
+
+ /**
+ * A translated human readable description of this attribute
+ */
+ QString description() const;
+ void setDescription(const QString &description);
+
+ /**
+ * The minimum value possible for this sensor
+ * (i.e to show a CPU is between 0 and 100)
+ * Set min and max to 0 if not relevant
+ */
+ qreal min() const;
+ void setMin(const qreal min);
+ /**
+ * The maximum value possible for this attribute
+ */
+ qreal max() const;
+ void setMax(const qreal max);
+
+ KSysGuard::Unit unit() const;
+ void setUnit(KSysGuard::Unit unit);
+
+ /**
+ * The last stored value for a given process
+ */
+ QVariant data(KSysGuard::Process *process);
+
+ /**
+ * Updates the stored value for a given process
+ * Note stray processes will be automatically expunged
+ */
+ void setData(KSysGuard::Process *process, const QVariant &value);
+ /**
+ * Remove an attribute from our local cache
+ */
+ void clearData(KSysGuard::Process *process);
+
+Q_SIGNALS:
+ void dataChanged(KSysGuard::Process *process);
+ void enabledChanged(bool enabled);
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+}
diff --git a/processcore/process_data_provider.cpp b/processcore/process_data_provider.cpp
new file mode 100644
index 0000000..363e814
--- /dev/null
+++ b/processcore/process_data_provider.cpp
@@ -0,0 +1,95 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "process_data_provider.h"
+#include "processes.h"
+#include "process_attribute.h"
+
+using namespace KSysGuard;
+
+class KSysGuard::ProcessDataProvider::Private
+{
+public:
+ KSysGuard::Processes* m_processes;
+ QVector<ProcessAttribute *> m_attributes;
+ bool m_enabled = false;
+};
+
+ProcessDataProvider::ProcessDataProvider(QObject *parent, const QVariantList &args)
+ : QObject(parent),
+ d(new Private)
+{
+ //cast is needed to allow us to use KPluginFactory, but not have null pointers during subclass construction
+ auto procList = qobject_cast<KSysGuard::Processes*>(parent);
+ Q_ASSERT(procList);
+ d->m_processes = procList;
+
+ Q_UNUSED(args)
+}
+
+ProcessDataProvider::~ProcessDataProvider()
+{
+}
+
+KSysGuard::Processes* ProcessDataProvider::processes() const
+{
+ return d->m_processes;
+}
+
+KSysGuard::Process *ProcessDataProvider::getProcess(long pid)
+{
+ auto process = d->m_processes->getProcess(pid);
+ if (!process) {
+ processes()->updateOrAddProcess(pid);
+ }
+ process = processes()->getProcess(pid);
+ return process;
+}
+
+QVector<ProcessAttribute *> ProcessDataProvider::attributes() const
+{
+ return d->m_attributes;
+}
+
+bool ProcessDataProvider::enabled() const
+{
+ return d->m_enabled;
+}
+
+void ProcessDataProvider::addProcessAttribute(ProcessAttribute *attribute)
+{
+ d->m_attributes << attribute;
+ connect(attribute, &ProcessAttribute::enabledChanged, this, [this](bool enabled) {
+ if (enabled == d->m_enabled) {
+ return;
+ }
+ bool wasEnabled = d->m_enabled;
+
+ d->m_enabled = std::any_of(d->m_attributes.constBegin(), d->m_attributes.constEnd(), [](ProcessAttribute *p) {
+ return p->enabled();
+ });
+
+ if (d->m_enabled != wasEnabled) {
+ handleEnabledChanged(d->m_enabled);
+ }
+ });
+}
+
+
+
diff --git a/processcore/process_data_provider.h b/processcore/process_data_provider.h
new file mode 100644
index 0000000..5139693
--- /dev/null
+++ b/processcore/process_data_provider.h
@@ -0,0 +1,96 @@
+/*
+ Copyright (c) 2019 David Edmundson <davidedmundson@kde.org>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#pragma once
+
+#include <QObject>
+#include <QVariant>
+
+namespace KSysGuard {
+
+class Processes;
+class Process;
+class ProcessAttribute;
+
+/**
+ * Base class for a process plugin data
+ * Plugins provide a list of additional attributes, which in turn have data about a given process
+ */
+class Q_DECL_EXPORT ProcessDataProvider : public QObject
+{
+ Q_OBJECT
+
+public:
+ ProcessDataProvider(QObject *parent, const QVariantList &args);
+ ~ProcessDataProvider() override;
+
+ /**
+ * Accessors for process information matching
+ */
+ KSysGuard::Processes* processes() const;
+
+ /**
+ * Returns a new process object for a given PID
+ * This will update the process list if this PID does not exist yet
+ * This may return a null pointer
+ */
+ KSysGuard::Process * getProcess(long pid);
+
+ /**
+ * A list of all process attributes provided by this plugin
+ * It is expected to remain constant through the lifespan of this class
+ */
+ QVector<ProcessAttribute *> attributes() const;
+
+ /**
+ * Called when processes should be updated if manually polled
+ * Plugins can however update at any time if enabled
+ */
+ virtual void update()
+ {}
+
+ /**
+ * True when at least one attribute from this plugin is subscribed
+ */
+ bool enabled() const;
+
+ virtual void handleEnabledChanged(bool enabled)
+ {
+ Q_UNUSED(enabled)
+ }
+
+ // for any future compatibility
+ virtual void virtual_hook(int id, void *data)
+ {
+ Q_UNUSED(id)
+ Q_UNUSED(data)
+ }
+
+protected:
+ /**
+ * Register a new process attribute
+ * Process attributes should be created in the plugin constuctor and must live for the duration the plugin
+ */
+ void addProcessAttribute(ProcessAttribute *attribute);
+
+private:
+ class Private;
+ QScopedPointer<Private> d;
+};
+
+}
diff --git a/processcore/processes.cpp b/processcore/processes.cpp
index e6f67db..2e4da96 100644
--- a/processcore/processes.cpp
+++ b/processcore/processes.cpp
@@ -354,7 +354,7 @@ void Processes::processesUpdated() {
}
d->mProcessedLastTime = beingProcessed; //update the set for next time this function is called
- return;
+ emit updated();
}
void Processes::Private::markProcessesAsEnded(long pid)
diff --git a/processcore/processes.h b/processcore/processes.h
index d2fe0d4..29d489d 100644
--- a/processcore/processes.h
+++ b/processcore/processes.h
@@ -242,6 +242,8 @@ namespace KSysGuard
* We have finished moving the process
*/
void endMoveProcess();
+
+ void updated();
protected:
class Private;
Private *d;
diff --git a/processcore/unit.cpp b/processcore/unit.cpp
new file mode 100644
index 0000000..e8a395a
--- /dev/null
+++ b/processcore/unit.cpp
@@ -0,0 +1,3 @@
+#include "unit.h"
+
+#include "moc_unit.cpp"
diff --git a/processcore/unit.h b/processcore/unit.h
new file mode 100644
index 0000000..5ad3f57
--- /dev/null
+++ b/processcore/unit.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
+
+ This library 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 of the License, or (at your option) any later version.
+
+ This library 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 library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#pragma once
+
+// Qt
+#include <QMetaType>
+
+namespace KSysGuard
+{
+Q_DECL_EXPORT Q_NAMESPACE
+
+/**
+ * This enum type is used to specify metric prefixes.
+ */
+enum MetricPrefix {
+ MetricPrefixAutoAdjust = -1,
+ MetricPrefixUnity = 0,
+ MetricPrefixKilo,
+ MetricPrefixMega,
+ MetricPrefixGiga,
+ MetricPrefixTera,
+ MetricPrefixPeta,
+ MetricPrefixLast = MetricPrefixPeta
+};
+Q_ENUM_NS(MetricPrefix)
+
+/**
+ * This enum types is used to specify units.
+ */
+enum Unit {
+ UnitInvalid = -1,
+ UnitNone = 0,
+
+ // Byte size units.
+ UnitByte = 100,
+ UnitKiloByte = MetricPrefixKilo + UnitByte,
+ UnitMegaByte = MetricPrefixMega + UnitByte,
+ UnitGigaByte = MetricPrefixGiga + UnitByte,
+ UnitTeraByte = MetricPrefixTera + UnitByte,
+ UnitPetaByte = MetricPrefixPeta + UnitByte,
+
+ // Data rate units.
+ UnitByteRate = 200,
+ UnitKiloByteRate = MetricPrefixKilo + UnitByteRate,
+ UnitMegaByteRate = MetricPrefixMega + UnitByteRate,
+ UnitGigaByteRate = MetricPrefixGiga + UnitByteRate,
+ UnitTeraByteRate = MetricPrefixTera + UnitByteRate,
+ UnitPetaByteRate = MetricPrefixPeta + UnitByteRate,
+
+ // Frequency.
+ UnitHertz = 300,
+ UnitKiloHertz = MetricPrefixKilo + UnitHertz,
+ UnitMegaHertz = MetricPrefixMega + UnitHertz,
+ UnitGigaHertz = MetricPrefixGiga + UnitHertz,
+ UnitTeraHertz = MetricPrefixTera + UnitHertz,
+ UnitPetaHertz = MetricPrefixPeta + UnitHertz,
+
+ // Time units.
+ UnitBootTimestamp = 400,
+ UnitSecond,
+ UnitTime,
+
+ // Misc units.
+ UnitCelsius = 500,
+ UnitDecibelMilliWatts,
+ UnitPercent,
+ UnitRate,
+ UnitRpm,
+ UnitVolt,
+ UnitWatt,
+};
+Q_ENUM_NS(Unit)
+
+} // namespace KSysGuard
diff --git a/processui/ProcessModel.cpp b/processui/ProcessModel.cpp
index b66b47f..9018c54 100644
--- a/processui/ProcessModel.cpp
+++ b/processui/ProcessModel.cpp
@@ -26,8 +26,12 @@
#include "ProcessModel_p.h"
#include "timeutil.h"
-#include "processcore/processes.h"
+#include "processcore/extended_process_list.h"
+#include "processcore/formatter.h"
#include "processcore/process.h"
+#include "processcore/process_attribute.h"
+#include "processcore/process_data_provider.h"
+
#include "processui_debug.h"
#include <kcolorscheme.h>
@@ -350,7 +354,11 @@ bool ProcessModel::lessThan(const QModelIndex &left, const QModelIndex &right) c
}
}
//Sort by the display string if we do not have an explicit sorting here
- return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString();
+
+ if (data(left, ProcessModel::PlainValueRole).toInt() == data(right, ProcessModel::PlainValueRole).toInt()) {
+ return data(left, Qt::DisplayRole).toString() < data(right, Qt::DisplayRole).toString();
+ }
+ return data(left, ProcessModel::PlainValueRole).toInt() < data(right, ProcessModel::PlainValueRole).toInt();
}
ProcessModel::~ProcessModel()
@@ -493,7 +501,7 @@ void ProcessModelPrivate::setupProcesses() {
q->endResetModel();
}
- mProcesses = new KSysGuard::Processes(mHostName);
+ mProcesses = new KSysGuard::ExtendedProcesses();
connect( mProcesses, &KSysGuard::Processes::processChanged, this, &ProcessModelPrivate::processChanged);
connect( mProcesses, &KSysGuard::Processes::beginAddProcess, this, &ProcessModelPrivate::beginInsertRow);
@@ -505,6 +513,16 @@ void ProcessModelPrivate::setupProcesses() {
connect( mProcesses, &KSysGuard::Processes::endMoveProcess, this, &ProcessModelPrivate::endMoveRow);
mNumProcessorCores = mProcesses->numberProcessorCores();
if(mNumProcessorCores < 1) mNumProcessorCores=1; //Default to 1 if there was an error getting the number
+
+ mExtraAttributes = mProcesses->attributes();
+ for (int i = 0 ; i < mExtraAttributes.count(); i ++) {
+ mExtraAttributes[i]->setEnabled(true); // In future we will toggle this based on column visibility
+
+ connect(mExtraAttributes[i], &KSysGuard::ProcessAttribute::dataChanged, this, [this, i](KSysGuard::Process *process) {
+ const QModelIndex index = q->getQModelIndex(process, mHeadings.count() + i);
+ emit q->dataChanged(index, index);
+ });
+ }
}
#if HAVE_X11
@@ -647,7 +665,7 @@ int ProcessModel::rowCount(const QModelIndex &parent) const
int ProcessModel::columnCount ( const QModelIndex & ) const
{
- return d->mHeadings.count();
+ return d->mHeadings.count() + d->mExtraAttributes.count();
}
bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) const
@@ -676,7 +694,7 @@ bool ProcessModel::hasChildren ( const QModelIndex & parent = QModelIndex() ) co
QModelIndex ProcessModel::index ( int row, int column, const QModelIndex & parent ) const
{
if(row<0) return QModelIndex();
- if(column<0 || column >= d->mHeadings.count() ) return QModelIndex();
+ if(column<0 || column >= columnCount() ) return QModelIndex();
if(d->mSimple) {
if( parent.isValid()) return QModelIndex();
@@ -968,8 +986,18 @@ QVariant ProcessModel::headerData(int section, Qt::Orientation orientation,
{
if(orientation != Qt::Horizontal)
return QVariant();
- if(section < 0 || section >= d->mHeadings.count())
+ if(section < 0)
return QVariant(); //is this needed?
+
+ if (section >= d->mHeadings.count() && section < columnCount()) {
+ int attr = section - d->mHeadings.count();
+ switch (role) {
+ case Qt::DisplayRole:
+ return d->mExtraAttributes[attr]->shortName();
+ }
+ return QVariant();
+ }
+
switch( role ) {
case Qt::TextAlignmentRole:
{
@@ -1263,12 +1291,39 @@ QString ProcessModelPrivate::getUsernameForUser(long uid, bool withuid) const {
QVariant ProcessModel::data(const QModelIndex &index, int role) const
{
//This function must be super duper ultra fast because it's called thousands of times every few second :(
- //I think it should be optomised for role first, hence the switch statement (fastest possible case)
+ //I think it should be optimised for role first, hence the switch statement (fastest possible case)
if (!index.isValid()) {
return QVariant();
}
+
+ if (index.column() > columnCount()) {
+ return QVariant();
+ }
+ //plugin stuff first
if (index.column() >= d->mHeadings.count()) {
+ int attr = index.column() - d->mHeadings.count();
+ switch (role) {
+ case ProcessModel::PlainValueRole: {
+ KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer());
+ const QVariant value = d->mExtraAttributes[attr]->data(process);
+ return value;
+ }
+ case Qt::DisplayRole: {
+ KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer());
+ const QVariant value = d->mExtraAttributes[attr]->data(process);
+ return KSysGuard::Formatter::formatValue(value, d->mExtraAttributes[attr]->unit());
+ }
+ case Qt::TextAlignmentRole: {
+ KSysGuard::Process *process = reinterpret_cast< KSysGuard::Process * > (index.internalPointer());
+ const QVariant value = d->mExtraAttributes[attr]->data(process);
+ if (value.canConvert(QMetaType::LongLong)
+ && static_cast<QMetaType::Type>(value.type()) != QMetaType::QString) {
+ return Qt::AlignRight + Qt::AlignVCenter;
+ }
+ return Qt::AlignLeft + Qt::AlignVCenter;
+ }
+ }
return QVariant();
}
@@ -2033,11 +2088,7 @@ void ProcessModel::setupHeader() {
headings << i18nc("process heading", "Total Memory");
if(d->mHeadings.isEmpty()) { // If it's empty, this is the first time this has been called, so insert the headings
- beginInsertColumns(QModelIndex(), 0, headings.count()-1);
- {
- d->mHeadings = headings;
- }
- endInsertColumns();
+ d->mHeadings = headings;
} else {
// This was called to retranslate the headings. Just use the new translations and call headerDataChanged
Q_ASSERT(d->mHeadings.count() == headings.count());
diff --git a/processui/ProcessModel_p.h b/processui/ProcessModel_p.h
index ecb6a1b..366e14d 100644
--- a/processui/ProcessModel_p.h
+++ b/processui/ProcessModel_p.h
@@ -22,7 +22,7 @@
#ifndef PROCESSMODEL_P_H_
#define PROCESSMODEL_P_H_
-#include <processcore/process.h>
+#include <processcore/extended_process_list.h>
#include "ProcessModel.h"
#include <kuser.h>
@@ -182,7 +182,7 @@ class ProcessModelPrivate : public QObject
long long mMemTotal; ///< the total amount of physical memory in kb in the machine. We can used this to determine the percentage of memory an app is using
int mNumProcessorCores; ///< The number of (enabled) processor cores in the this machine
- KSysGuard::Processes *mProcesses; ///< The processes instance
+ KSysGuard::ExtendedProcesses *mProcesses; ///< The processes instance
QPixmap mBlankPixmap; ///< Used to pad out process names which don't have an icon
@@ -208,6 +208,8 @@ class ProcessModelPrivate : public QObject
/** Storage for the history entries. We need one per percentage column. */
QHash<KSysGuard::Process *, QVector<ProcessModel::PercentageHistoryEntry>> mMapProcessCPUHistory;
+ QVector<KSysGuard::ProcessAttribute*> mExtraAttributes;
+
#ifdef HAVE_XRES
bool mHaveXRes; ///< True if the XRes extension is available at run time
QMap<qlonglong, XID> mXResClientResources;
davidedmundson edited the content of this paste. (Show Details)Sep 18 2019, 12:29 PM
davidedmundson changed the title of this paste from untitled to Masterwork From Distant Lands.