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

224 lines
7.3 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @RDE_HEADER@
* Plugin to watch the currently active Exercise and keep track of the Exc Name, Exc Phase, etc.
* $Id$
* $HeadURL$
* $Author$
* Created by Mike Wille, SLSE, 2017-09-29
*/
#include "exm_watch_gui_plugin.h"
#include <LtsSession/lts_session.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <LtsWidgets/lts_base_layout_widget.h>
#include <ExerciseManagement/exm_translation.h>
#include <ngltools/ngltools_dtg.h>
namespace ExerciseManagement
{
std::shared_ptr<GuiPluginBase::Interface> GuiPlugin::createGuiInterface(LtsSession::LtsSession *session)
{
return std::make_shared<InterfaceImpl>(session);
}
InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session)
: GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Exm.Watch"))
, m_dtc(nullptr)
, m_isDeleted(false)
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<ExerciseManagement::DataInterface>(m_dtc))
return false;
return true;
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
{
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
plData.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
plData.directFunc = [this](const LtsWidgets::PluginData &)
{
connect(m_dtc.get(), &ExerciseManagement::Interface::Dtc::exerciseChanged,
this, &InterfaceImpl::slotExerciseChanged);
connect(m_dtc.get(), &ExerciseManagement::Interface::Dtc::exercisePhaseChanged,
this, &InterfaceImpl::slotExercisePhaseChanged);
if (m_session->isInitializationDone())
slotSetExerciseData();
else
connect(m_session, &LtsSession::LtsSession::signalDoneInitializingSession,
this, &InterfaceImpl::slotSetExerciseData); // wait until session is initialized
};
ret.append(plData);
}
return ret;
}
LtsWidgets::ExcState InterfaceImpl::convertState(ExerciseState state)
{
int underlying = state.underlying() - 1;
if (underlying >= 0)
{
int i_state = (1 << static_cast<int>(underlying));
return static_cast<LtsWidgets::ExcState>(i_state);
}
return LtsWidgets::ExcState::eUnknown;
}
void InterfaceImpl::clearInterfaces()
{
m_dtc = nullptr;
}
QColor InterfaceImpl::exerciseStateColor(ExerciseManagement::ExerciseState state)
{
switch(state.underlying())
{
case ExerciseState::Unknown: return Qt::black;
case ExerciseState::Created: return Qt::cyan;
case ExerciseState::Started: return Qt::darkGreen;
case ExerciseState::Paused: return Qt::darkYellow;
case ExerciseState::Stopped: return Qt::magenta;
case ExerciseState::Terminated: return Qt::red;
}
return QColor();
}
void InterfaceImpl::slotExerciseChanged(const ExerciseManagement::Exercise &data, DataModification modType)
{
TRACE_LOG(m_logger) << LOGFUNCTION << " START, this=" << this << ", exId=" << data.id();
if (m_isDeleted)
return;
if (data.id() != m_session->exerciseId())
return;
switch (modType)
{
case DataModification::eRemoved:
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " eRemoved" << ", this=" << this << ", exId=" << data.id();
m_previouslyRemoved = true;
WARNING_LOG(m_logger) << "Partition has been removed from the DDS bus! Session: " << m_session->toString();
if (m_session->baseLayout())
m_session->baseLayout()->showMessage(tr("Connection to server lost"), tr("Trying to reconnect. You will be notified."), LtsWidgets::LtsNotificationBox::MessageType::Error);
break;
}
case DataModification::eAdded:
{
WARNING_LOG(m_logger) << LOGFUNCTION << ", Partition added to DDS bus! Session: " << m_session->toString();
DEBUG_LOG(m_logger) << LOGFUNCTION << " eAdded, m_previouslyRemoved=" << m_previouslyRemoved << ", this=" << this << ", exId=" << data.id();
if (m_previouslyRemoved)
{
m_previouslyRemoved = false;
if (m_session->baseLayout())
m_session->baseLayout()->showMessage(tr("Successfully reconnected"), tr("Connection to server was successfully reestablished."), LtsWidgets::LtsNotificationBox::MessageType::Success);
}
Q_FALLTHROUGH();
}
case DataModification::eModified:
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " eModified, m_previouslyRemoved=" << m_previouslyRemoved << ", this=" << this << ", exId=" << data.id();
slotSetExerciseData();
break;
}
}
TRACE_LOG(m_logger) << LOGFUNCTION << " END, this=" << this << ", exId=" << data.id();
}
void InterfaceImpl::slotExercisePhaseChanged(const ExerciseManagement::ExercisePhase &data, DataModification modType)
{
Q_UNUSED(modType);
if (m_isDeleted)
return;
if (data.exerciseId() != m_session->exerciseId() ||
data.id() != m_session->exerciseData()->phId)
return;
slotExerciseChanged(m_dtc->exercise(m_session->exerciseId()), DataModification::eModified);
}
QString InterfaceImpl::partitionTypeString() const
{
switch (m_session->partitionType())
{
case IDL::PartitionType::Global: return QStringLiteral("<font color='grey'>%1</font>").arg(tr("Admin"));
case IDL::PartitionType::Exercise: return QStringLiteral("<font color='green'>%1</font>").arg(tr("Live"));
case IDL::PartitionType::Replay: return QStringLiteral("<font color='red'>%1</font>").arg(tr("Replay"));
default: return tr("unknown");
}
}
void InterfaceImpl::slotSetExerciseData()
{
disconnect(m_session, &LtsSession::LtsSession::signalDoneInitializingSession,
this, nullptr);
LtsWidgets::ExerciseData exData;
// 26.06.2023, Norbert Thoden
// Sometimes the ScriptEditorEssentialsView doesn´t have any buttons at the right menue.
// Reason:
// "Partition has been removed from the DDS bus"
// So afterwards slotSetExerciseData has called.
// With a virgin dtc leads to invalid data Exercise.
// So add waitForHistoricalData :-)
// Addtionally:
// Within slotExerciseChanged it´s handled as not m_previouslyRemoved
// and 'break' had skipped the rest of the slot - especially eModified.
// Now: If DDS partiton is newly created, the slot is called,
// eAdded and via Q_FALLTHROUGH eModified is executed also!
// To avoid signalExerciseDataChanged to be emiited multiple times,
// data is checked (operator==())
m_dtc->waitForHistoricalDataExercise(2000);
m_dtc->waitForHistoricalDataExercisePhase(2000);
const ExerciseManagement::Exercise &ex = m_dtc->exercise(m_session->exerciseId());
if (ex.id() != m_session->exerciseId())
FATAL_LOG(m_logger) << LOGFUNCTION << ", requested exId and return exId do not match!!!";
// no assert here to not desturb debugging
const ExerciseManagement::ExercisePhase &ph = m_dtc->exercisePhase(ex.activePhaseId());
exData.exName = QString::fromStdString(ex.name());
exData.exDescription = QString::fromStdString(ex.description());
exData.exStateString = ExerciseManagement::toString(ex.state());
exData.exState = convertState(ex.state());
exData.exStateCol = exerciseStateColor(ex.state());
exData.partitionType = partitionTypeString();
exData.phId = ph.id();
exData.phName = QString::fromStdString(ph.name());
exData.phDescription = QString::fromStdString(ph.description());
m_session->setExerciseData(exData);
DTG::setTimezone(ex.defaultTimeZone(), false);
}
} // namespace ExerciseManagement