Files
qt5-legatus-legacy/Lts/Plugins/FreeSpace/Gui/fsp_gui_plugin.cpp
T
2026-08-13 18:33:10 +02:00

307 lines
8.5 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Gui Plugin for Free Space Monitor
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLTE, 2020-11-22
*/
#include "fsp_gui_plugin.h"
#include <LtsNotification/lts_notification.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <cmath>
#include <iostream>
#include <fstream>
#include <QTimer>
#include <QStorageInfo>
#include <QCoreApplication>
#include <QPainter>
#include <QImage>
#include <QGradient>
#include <QDebug>
namespace FreeSpace
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("FreeSpaceGui"))
{
connect(m_session, &LtsSession::LtsSession::signalDoneInitializingSession, // workaround to only receive the signal once
this, &InterfaceImpl::onInitDone);
}
void InterfaceImpl::onInitDone()
{
disconnect(m_session, &LtsSession::LtsSession::signalDoneInitializingSession,
this, nullptr); // workaround to only receive the signal once
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsWidgets::PluginData plData;
unsigned long dummy1;
double dummy2;
if (onStatusRAM(dummy1, dummy2))
{
// RAM
plData.identifier = QLatin1String("CreateFreeRamNoti");
plData.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
plData.directFunc = [this](const LtsWidgets::PluginData &)
{
m_notiStatusRam = m_session->createNotification(QStringLiteral("FreeRamMonitor"));
m_notiStatusRam->setIcon(QIcon(QStringLiteral("icon:usedspace-100.svg")));
// m_noti->setAction([this]()
// {
// new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), m_noti->tooltip(), tr("Current free disk space"));
// });
slotCheckFreeRamStatus();
QTimer *t = new QTimer(this);
t->setInterval(5000);
connect(t, &QTimer::timeout,
this, &InterfaceImpl::slotCheckFreeRamStatus);
t->start();
};
ret.append(plData);
}
// show free space indication only for MobileActionVehicle
// (taken from pre_edit_gui_plugin.cpp with small adaptions)
bool fakeMba = (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("MBA.Fake")) == QVariant(true));
if (!fakeMba)
{
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc;
if (!m_session->getDtc<AssetManagement::DataInterface>(asmDtc))
{
WARNING_LOG(m_logger) << "getDtc for AssetManagement::DataInterface failed.";
return {};
}
bool isAAR = asmDtc->isAARWorkstation(LtsSession::LtsSession::workstationName());
if (!isAAR)
{
DEBUG_LOG(m_logger) << "not a mba ws - no free space noti";
return ret;
}
}
else
WARNING_LOG(m_logger) << "fake mba";
plData.identifier = QLatin1String("CreateFreeSpaceNoti");
plData.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
plData.directFunc = [this](const LtsWidgets::PluginData &)
{
m_notiStatusHdd = m_session->createNotification(QStringLiteral("FreeSpaceMonitor"));
m_notiStatusHdd->setIcon(QIcon(QStringLiteral("icon:usedspace-100.svg")));
m_notiStatusHdd->setAction([this]()
{
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), m_notiStatusHdd->tooltip(), tr("Current free disk space"));
});
slotCheckFreeSpaceStatus();
QTimer *t = new QTimer(this);
t->setInterval(10000);
connect(t, &QTimer::timeout,
this, &InterfaceImpl::slotCheckFreeSpaceStatus);
t->start();
};
ret.append(plData);
return ret;
}
// copied from osc_selftest.cpp and adapted
bool InterfaceImpl::onStatusHDD(quint64 &freeSpaceBytes, double &usedSpacePercent)
{
QStorageInfo storage(QCoreApplication::applicationFilePath());
if (storage.isValid() && storage.isReady())
{
quint64 freeBytesAvailable = storage.bytesAvailable();
quint64 bytesAvailable = storage.bytesTotal();
double percent = bytesAvailable ? 100.0 * freeBytesAvailable / bytesAvailable : 0;
freeSpaceBytes = freeBytesAvailable;
usedSpacePercent = 100.0 - percent;
return true;
}
else
return false;
}
bool InterfaceImpl::onStatusRAM(unsigned long &freeRamKbytes, double &usedRamPercent)
{
freeRamKbytes = 0;
usedRamPercent = 0.0;
std::string key;
std::ifstream meminfo("/proc/meminfo");
if (!meminfo.is_open())
{
qWarning() << "cannot open /proc/meminfo";
return false;
}
unsigned long memTotal = 0;
unsigned long memAvailable = 0;
while (meminfo >> key)
{
if (key == "MemTotal:")
meminfo >> memTotal;
else if (key == "MemAvailable:")
meminfo >> memAvailable;
meminfo.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // ignore rest of the line after the value we need
}
qDebug() << "MemTotal" << memTotal
<< "MemAvailable" << memAvailable;
freeRamKbytes = memAvailable;
usedRamPercent = static_cast<double>(memTotal - memAvailable) / static_cast<double>(memTotal) * 100.0;
return true;
}
QImage renderRamImage(double usedRamPercent)
{
int size = 100;
QImage image(size, size, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
QColor color{Qt::darkRed};
if (usedRamPercent < 70.0)
color = Qt::green;
else if (usedRamPercent < 80.0)
color = Qt::yellow;
else if (usedRamPercent < 85.0)
color = qRgb(213, 200, 0); // darkyellow
else if (usedRamPercent < 90.0)
color = qRgb(255, 165, 0); // orange
else if (usedRamPercent < 95.0)
color = Qt::red;
QRadialGradient arcGradient(image.rect().center(), size * 0.6);
arcGradient.setColorAt(1.0, Qt::transparent);
arcGradient.setColorAt(0.0, color);
painter.setBrush(QBrush(arcGradient));
painter.setPen(QPen(Qt::NoPen)); // rect with no outter line
painter.drawEllipse(image.rect());
painter.end();
return image;
}
void InterfaceImpl::slotCheckFreeRamStatus()
{
if (!m_notiStatusRam)
return;
unsigned long freeRamKbytes;
double usedRamPercent;
if (!onStatusRAM(freeRamKbytes, usedRamPercent))
return;
m_notiStatusRam->setIcon(QPixmap::fromImage(renderRamImage(usedRamPercent)));
QString statusText(tr("Free memory: %1 (%2% used)").arg(readableSize(freeRamKbytes * 1024)).arg(std::round(usedRamPercent))); // text output of free space in readable unit
m_notiStatusRam->setToolTip(statusText);
}
void InterfaceImpl::slotCheckFreeSpaceStatus()
{
if (!m_notiStatusHdd)
return;
double usedSpacePercent = 0.0;
quint64 freeSpaceBytes = 0.0;
bool success = onStatusHDD(freeSpaceBytes, usedSpacePercent);
QString statusText;
QString filename;
if (!success)
{
statusText = tr("Error while reading disk space");
filename = QStringLiteral("icon:usedspace-100.svg");
}
else
{
int usedDiskSpaceFile = 0;
if (usedSpacePercent < 11) // this '11' thing ruins the easy 4-liner I had here first..
usedDiskSpaceFile = 0;
else if (usedSpacePercent < 21)
usedDiskSpaceFile = 20;
else if (usedSpacePercent < 41)
usedDiskSpaceFile = 40;
else if (usedSpacePercent < 61)
usedDiskSpaceFile = 60;
else if (usedSpacePercent < 81)
usedDiskSpaceFile = 80;
else
usedDiskSpaceFile = 100;
filename = QStringLiteral("icon:usedspace-%1.svg").arg(usedDiskSpaceFile);
statusText = tr("Free disk space: %1 (%2% used)").arg(readableSize(freeSpaceBytes)).arg(std::round(usedSpacePercent)); // text output of free space in readable unit
}
QString tooltip(statusText);
m_notiStatusHdd->setIcon(QIcon(filename));
m_notiStatusHdd->setToolTip(tooltip);
}
// copied from osc_selftest.cpp
QString InterfaceImpl::readableSize(quint64 bytes) const
{
if (bytes > TB)
return QStringLiteral("%1 TB").arg((double) bytes / TB, 0, 'f', 2);
else if (bytes > GB)
return QStringLiteral("%1 GB").arg((double) bytes / GB, 0, 'f', 2);
else if (bytes > MB)
return QStringLiteral("%1 MB").arg((double) bytes / MB, 0, 'f', 2);
else if (bytes > KB)
return QStringLiteral("%1 KB").arg((double) bytes / KB, 0, 'f', 2);
else
return QStringLiteral("%1 Bytes").arg(bytes);
}
} // namespace FreeSpace