/** * @RDE_HEADER@ * Notifcation plugin for TAB connection states * $Id$ * $HeadURL$ * $Author$ * Created by Philipp Dassow, SLST, 2017-09-19 */ #include "nme_battery_info_dialog.h" #include "nme_notification_gui_plugin.h" #include "nme_shutdown_dialog.h" #include #include #include #include #include #include #include namespace NmeaManagement { 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("NmeaGuiPlugin")) , m_tabDtc(nullptr) , m_tabFtc(nullptr) , m_notiBattery(nullptr) , m_notiOwnPosition(nullptr) { m_oudatedFirstBatteryTimer = new QTimer(this); m_oudatedSecondBatteryTimer = new QTimer(this); connect(m_oudatedFirstBatteryTimer, &QTimer::timeout, this,&InterfaceImpl::onOutdatedFirstBatteryTimerTimeout); connect(m_oudatedSecondBatteryTimer, &QTimer::timeout, this,&InterfaceImpl::onOutdatedSecondBatteryTimerTimeout); } InterfaceImpl::~InterfaceImpl() { delete m_notiBattery; delete m_notiOwnPosition; } QVector InterfaceImpl::getActions() { QVector ret; LtsWidgets::PluginData plData; plData.menuGroup = menuGroup(); plData.menuText = tr("Shutdown Radio Master"); plData.identifier = QLatin1String("ShutdownRadioMaster"); plData.menuIcon = QIcon(QLatin1String("icon:application-exit.svg")); plData.exercisePart = LtsWidgets::ExercisePart::eSpecial; plData.directFunc = [this](const LtsWidgets::PluginData &) { NmeBatteryInfoDialog *batteryDialog = new NmeBatteryInfoDialog(m_currentBatteryStateForId, m_tabDtc, m_tabFtc); m_session->addWidget(batteryDialog, menuGroup(), QStringLiteral("batteryInfo"), LtsWidgets::LayoutArea::eDialogTab); }; if (m_notiBattery != nullptr /*|| m_notiOwnPosition != nullptr*/) return QVector(); //TODO: Uncomment if necessary // m_notiOwnPosition = m_session->createNotification(QStringLiteral("Show own position")); // m_notiOwnPosition->setToolTip(tr("Show own position")); // m_notiOwnPosition->setIcon(QIcon(QStringLiteral("icon:/position.svg"))); // m_notiOwnPosition->setAction([this](){ // //TODO: What to do if something like that happend // }); m_notiBattery = m_session->createNotification(QStringLiteral("Radio Master Battery State")); updateBatteryLevel(); m_notiBattery->setAction([this](){ NmeBatteryInfoDialog *batteryDialog = new NmeBatteryInfoDialog(m_currentBatteryStateForId, m_tabDtc, m_tabFtc); m_session->addWidget(batteryDialog, menuGroup(), QStringLiteral("batteryInfo"), LtsWidgets::LayoutArea::eDialogTab); }); //setToolTip(); // ret.append(plData); return ret; } bool InterfaceImpl::fetchInterfaces() { //Dual Use while migrating from NmeaService to Nmea Tab Plugin if (!m_session->getDtc(m_tabDtc)) return false; if (!m_session->getFtc(m_tabFtc)) return false; if(!m_tabDtc->enableBatteryInfo()) return false; if(!m_tabDtc->enableBatteryAlarm()) return false; if(!m_tabDtc->enableServiceControl()) return false; if(!m_tabFtc->enableSetDevicePower()) return false; connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::batteryInfoChanged, this, &InterfaceImpl::onBatteryChanged); connect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::serviceControlChanged, this, &InterfaceImpl::onShutdownStateChanged); return true; } void InterfaceImpl::clearInterfaces() { disconnect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::batteryInfoChanged, this, &InterfaceImpl::onBatteryChanged); disconnect(m_tabDtc.get(), &TrainingAreaBase::Interface::Dtc::serviceControlChanged, this, &InterfaceImpl::onShutdownStateChanged); m_tabDtc = nullptr; m_tabFtc = nullptr; } /*! * \brief InterfaceImpl::onBatteryChanged * \param data * \param modType * \details * Receives Battery State and save them if changed * Paints new Icon and set new tooltip * If incoming BatteryState is under 2 (40%) and lower than last received state -> Show Warning */ void InterfaceImpl::onBatteryChanged(const TrainingAreaBase::BatteryInfo &dataArr, DataModification modType) { if(dataArr.equipmentNumber() != 1) return; auto data = dataArr.batteryStates().at(0); switch (modType) { case DataModification::eAdded: case DataModification::eModified: { if(m_hasConnection == false) { m_hasConnection = true; if (m_session->baseLayout() != nullptr) m_session->baseLayout()->showMessage(tr("The radio master is connected"), tr("Connection was successfully reestablished"), LtsWidgets::LtsNotificationBox::MessageType::Success); } if((data.batteryPercent() / 20) < m_currentBatteryStateForId.value(data.batteryPort()).batteryPercent() / 20 && data.batteryPercent() / 20 < 2) { QMessageBox batteryWarnBox; batteryWarnBox.setWindowTitle(tr("Battery Warning")); batteryWarnBox.setText(tr("The battery (%1) has only %2 \% left").arg(QString::fromStdString(data.serialNumber())).arg(data.batteryPercent())); //*20 = Real percentage batteryWarnBox.exec(); } m_currentBatteryStateForId.insert(data.batteryPort(), data); updateBatteryLevel(); if(data.batteryPort() == 0) m_oudatedFirstBatteryTimer->start(30000); else if(data.batteryPort() == 1) m_oudatedSecondBatteryTimer->start(30000); break; } case DataModification::eRemoved: { m_currentBatteryStateForId.remove(data.batteryPort()); updateBatteryLevel(); break; } } } /*! * \brief InterfaceImpl::onShutdownStateChanged * \author Niklas Schmidt * \param data * \param modType * \details * Receives notification for the sthutdown state of RadioMaster * Than show QMessageBox with shutdown state */ void InterfaceImpl::onShutdownStateChanged(const TrainingAreaBase::ServiceControl &data, DataModification modType) { if(data.equipmentNumber() != 1) return; switch (modType) { case DataModification::eAdded: case DataModification::eModified: { if(data.serviceControlState().underlying() == TrainingAreaBase::ServiceControlEnum::STOP) { m_hasConnection = false; if (m_session->baseLayout() != nullptr) m_session->baseLayout()->showMessage(tr("The radio master is shut down"), tr("The batteries can be disconnected."), LtsWidgets::LtsNotificationBox::MessageType::Error); } //shutdownInfoBox.exec(); break; } case DataModification::eRemoved: { } } } /*! * \brief InterfaceImpl::onOutdatedFirstBatteryTimerTimeout * \details * Timeouted if no new incoming data is available * Updates battery icon to unknown state */ void InterfaceImpl::onOutdatedFirstBatteryTimerTimeout() { //Default values for undefined state if(m_currentBatteryStateForId.size() < 2) { m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage())); setToolTip(); m_currentBatteryStateForId.clear(); return; } m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage(99, m_currentBatteryStateForId.value(1).batteryPercent() / 20))); setToolTip(99, m_currentBatteryStateForId.value(1).batteryPercent() / 20); m_currentBatteryStateForId.remove(0); } /*! * \brief InterfaceImpl::onOutdatedSecondBatteryTimerTimeout * \details * Timeouted if no new incoming data is available * Updates battery icon to unknown state */ void InterfaceImpl::onOutdatedSecondBatteryTimerTimeout() { if(m_currentBatteryStateForId.size() < 2) { m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage())); setToolTip(); m_currentBatteryStateForId.clear(); return; } //Default values for undefined state m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage(m_currentBatteryStateForId.value(0).batteryPercent() / 20, 99))); setToolTip(m_currentBatteryStateForId.value(0).batteryPercent() / 20, 99); m_currentBatteryStateForId.remove(1); } /*! * \brief InterfaceImpl::setToolTip * \param firstBattery * \author Niklas Schmidt * \param secondBattery * \details Changes Tooltip for BatteryState Notification */ void InterfaceImpl::setToolTip(int firstBattery, int secondBattery) { QString tooltip; if(firstBattery == 99) tooltip = tr("First Battery Level: Unknown %1").arg(QStringLiteral("\n")); else tooltip = tr("First Battery Level: ") + QString::number(firstBattery * 20) + QStringLiteral("% \n"); if(secondBattery == 99) tooltip += tr("Second Battery Level: Unknown"); else tooltip += tr("Second Battery Level: ") + QString::number(secondBattery * 20) + QStringLiteral("%"); m_notiBattery->setToolTip(tooltip); } /*! * \brief InterfaceImpl::renderBatteryImage * \author Niklas Schmidt * \param firstBatteryState * \param secondBatteryState * \details * This method paints the icon for battery state * * Battery Unknown = Only Outline and Questionmark in middle * Battery 0% = 5 Red Bars * Battery 20% = 1 Red Bar * Battery 40% = 2 Yellow Bar * Battery 60% = 3 Green Bars * Battery 80% = 4 Green Bras * Battery 100% = 5 Green Bars * * BatteryState Int -> 0 = Empty ... 5 = Full | 99 = Unknown * \return */ QImage InterfaceImpl::renderBatteryImage(int firstBatteryState, int secondBatteryState) { int firstBattery = firstBatteryState; int secondBattery = secondBatteryState; int size = 100; QImage image(size, size, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(&image); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); if(firstBattery != 99) { painter.setBrush(QBrush(Qt::green, Qt::SolidPattern)); if(firstBattery < 3) painter.setBrush(QBrush(Qt::yellow, Qt::SolidPattern)); if(firstBattery < 2) painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); if(firstBattery == 0) { painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); firstBattery = 5; // To paint all 5 bars red } //For first battery (upper bar) if (firstBattery > 0) painter.drawRect(00, 00, 18, 40); if (firstBattery > 1) painter.drawRect(20, 00, 18, 40); if (firstBattery > 2) painter.drawRect(40, 00, 18, 40); if (firstBattery > 3) painter.drawRect(60, 00, 18, 40); if (firstBattery > 4) painter.drawRect(80, 00, 18, 40); } if(secondBattery != 99) { painter.setBrush(QBrush(Qt::green, Qt::SolidPattern)); if(secondBattery < 3) painter.setBrush(QBrush(Qt::yellow, Qt::SolidPattern)); if(secondBattery < 2) painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); if(secondBattery == 0) { painter.setBrush(QBrush(Qt::red, Qt::SolidPattern)); secondBattery = 5; // To paint all 5 bars red } //For second battery (lower bar) if (secondBattery > 0) painter.drawRect(00, 60, 18, 40); if (secondBattery > 1) painter.drawRect(20, 60, 18, 40); if (secondBattery > 2) painter.drawRect(40, 60, 18, 40); if (secondBattery > 3) painter.drawRect(60, 60, 18, 40); if (secondBattery > 4) painter.drawRect(80, 60, 18, 40); } QFont font = painter.font() ; font.setPointSize(30); painter.setFont(font); painter.setBrush(QBrush(Qt::black, Qt::NoBrush)); if(firstBattery == 99) //If Unknown BatteryState { painter.setPen(Qt::black); painter.drawText(45,35, QStringLiteral("?")); } // Draw Outline for whole Battery painter.setPen(Qt::black); painter.drawRect(00,00,100,40); painter.setBrush(QBrush(Qt::black, Qt::NoBrush)); if(secondBattery == 99) //If Unknown BatteryState { painter.setPen(Qt::black); painter.drawText(45,92, QStringLiteral("?")); } // Draw Outline for whole Battery painter.setPen(Qt::black); painter.drawRect(00,60,100,40); // 'marking': // painter.setPen(QPen(Qt::NoPen)); // rect with no outter line painter.end(); return image; } /*! * \brief InterfaceImpl::updateBatteryLevel * \details Changes the icon of battery state and change Tooltip */ void InterfaceImpl::updateBatteryLevel() { if(!m_notiBattery) return; if(m_currentBatteryStateForId.isEmpty()) { setToolTip(); m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage())); return; } int firstBatteryState = m_currentBatteryStateForId.value(0).batteryPercent() / 20; int secondBatteryState = m_currentBatteryStateForId.value(1).batteryPercent() / 20; if(m_currentBatteryStateForId.values().length() == 2) { setToolTip(firstBatteryState, secondBatteryState); m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage(firstBatteryState, secondBatteryState))); } else if(m_currentBatteryStateForId.values().length() == 1) { if(m_currentBatteryStateForId.first().batteryPort() == 0) { m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage(firstBatteryState, 99))); setToolTip(firstBatteryState, 99); } else if(m_currentBatteryStateForId.first().batteryPort() == 1) { m_notiBattery->setIcon(QPixmap::fromImage(renderBatteryImage(99,secondBatteryState))); setToolTip(99,secondBatteryState); } } } } // namespace NmeaManagement