307 lines
8.5 KiB
C++
Executable File
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
|