/** * @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 #include #include #include #include namespace ExerciseManagement { std::shared_ptr GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared(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(m_dtc)) return false; return true; } QVector InterfaceImpl::getActions() { QVector 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(underlying)); return static_cast(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("%1").arg(tr("Admin")); case IDL::PartitionType::Exercise: return QStringLiteral("%1").arg(tr("Live")); case IDL::PartitionType::Replay: return QStringLiteral("%1").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