/** * @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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace FreeSpace { std::shared_ptr GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared(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 InterfaceImpl::getActions() { QVector 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 asmDtc; if (!m_session->getDtc(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::max(), '\n'); // ignore rest of the line after the value we need } qDebug() << "MemTotal" << memTotal << "MemAvailable" << memAvailable; freeRamKbytes = memAvailable; usedRamPercent = static_cast(memTotal - memAvailable) / static_cast(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