/** * @RDE_HEADER@ * GUI Plugin for SituationReplayManagement - Replay Management * $Id$ * $HeadURL$ * $Author$ * Created by Patric Karwar, SLSE, 2016-07-19 */ #include "replay_management_gui_plugin.h" #include "replay_dialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace SituationReplayManagement { std::shared_ptr GuiPlugin::createGuiInterface(LtsSession::LtsSession *session) { return std::make_shared(session); } InterfaceImpl::InterfaceImpl(LtsSession::LtsSession *session) : GuiPluginBase::Interface(session, getLogger("Plugins.Gui.Srm.ReplayManagement")) , m_requestHelper(nullptr) {} InterfaceImpl::~InterfaceImpl() { } bool InterfaceImpl::fetchInterfaces() { if (!m_session->getDtc(m_coreDtc)) return false; if (!m_session->getForeignDataInterface(m_sitRepIfc)) return false; if (!m_session->getForeignGuiInterface(m_fltParticipantIfc)) { DEBUG_LOG(m_logger) << "getForeignGuiInterface for Filter Management Participant Gui failed."; return false; } if (!m_session->getForeignGuiInterface(m_fltAesIfc)) { DEBUG_LOG(m_logger) << "getForeignGuiInterface for Filter Management Aes Gui failed."; return false; } if (!m_session->getFtc(m_fltFtc)) { DEBUG_LOG(m_logger) << "getFtc for FilterManagement::Interface failed."; return false; } return true; } void InterfaceImpl::clearInterfaces() { m_coreDtc = nullptr; m_sitRepIfc = nullptr; m_fltParticipantIfc = nullptr; m_fltAesIfc = nullptr; } QVector InterfaceImpl::getActions() { QVector ret; #ifndef LTS_DEBUG if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("ShowReplayManagementAction")) == QVariant(true)) #endif { LtsWidgets::PluginData plData; plData.menuGroup = menuGroup(); plData.layoutArea = LtsWidgets::LayoutArea::eDialogTab; plData.menuText = tr("Replay Management"); plData.identifier = QLatin1String("ReplayManagement"); plData.menuIcon = QIcon(QLatin1String("icon:playback_situation.svg")); plData.operatorRight = OperatorRights::ReplayManagement; plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction; plData.createWidgetFunc = [this](QWidget *parent) { return LtsWidgets::initDialog(new SituationReplayManagementDialog(m_session, parent), m_coreDtc, m_sitRepIfc); }; ret.append(plData); } LtsWidgets::PluginData plData; plData.menuGroup = menuGroup(); plData.menuText = tr("Situation Playback"); plData.identifier = QLatin1String("ReplayManagementStart"); plData.menuIcon = QIcon(QLatin1String("icon:playback_situation_start.svg")); plData.operatorRight = OperatorRights::ReplayManagement; if (m_session->partitionType() == IDL::PartitionType::Exercise) { plData.exercisePart = LtsWidgets::ExercisePart::eAfterAction; plData.directFunc = [this](const LtsWidgets::PluginData &) { return startReplay(); }; ret.append(plData); } // Zusaetzlich auch in 'Apps' aufschalten //????? wie kann man das auch in 'Apps' anzeigen die keinen exercisePart haben ?? z.B. RessourcenManagement, Timeline plData.menuGroup = tr("Apps"); plData.exercisePart = LtsWidgets::ExercisePart::eSpecial; plData.directFunc = [this](const LtsWidgets::PluginData &) { return startReplay(); }; ret.append(plData); return ret; } QString InterfaceImpl::menuGroup() const { return tr("Playbacks"); } void InterfaceImpl::startReplay() // blocks! { std::unique_ptr _(new LtsWidgets::LtsWaitDialog(tr("Waiting for Situation Replay app"))); int replayId; try { replayId = m_sitRepIfc->replayPartitionCreateRequest(m_session->partitionId(), LtsSessionData::LtsSessionData::getInstance()->getWorkstationId(), LtsSessionData::LtsSessionData::getInstance()->getOperatorId(), Core::ReplayType::SituationData); } catch(...) { new LtsWidgets::LtsMessageDialogNew(m_session->baseLayout(), tr("Failed to start replay partition for replay!")); return; } bool found = false; Core::ReplayPartition rp; for (int i = 0; i < 40; i++) { rp = m_coreDtc->replayPartition(replayId); if (rp.id() == replayId) { found = true; break; } try{ LtsUtils::awaitTimeout(250); }catch(...){} } auto rmPartFn = [this, replayId]() { try { m_sitRepIfc->replayPartitionRemoveRequest(replayId, LtsSessionData::LtsSessionData::getInstance()->getWorkstationId(), LtsSessionData::LtsSessionData::getInstance()->getOperatorId()); // NOTE: unfortunately waits... } catch (...) { ERROR_LOG(m_logger) << "[timeout] Failed to remove failed-to-start replay. domainId: " << m_session->domainId() << " - replay id: " << replayId << " - url " << m_session->tcpConnectionUrl().toString(); } }; if (!found) { LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Error trying to create a replay session")); WARNING_LOG(m_logger) << "[timeout] Error while trying to create a replay session: domainId: " << m_session->domainId() << " - replay partition does not exist - replay id: " << replayId << " - url " << m_session->tcpConnectionUrl().toString(); rmPartFn(); return; } startReplayApp(rp); // calls done() on global wait dlg } void InterfaceImpl::startReplayApp(const Core::ReplayPartition &data) { m_aesTransfered = false; m_symbolAppearanceTransfered = false; m_data = data; // could we supply the operator-specific default settings??? // available vi opm plugin (OperatorManagement -> defaultFilterPresetId)??? if (!transferFilter(data)) ERROR_LOG(m_logger) << LOGFUNCTION << " transferFilter failed."; // to avoid race conditions, continued in 'startReplayAppInternal', called by // onAesFilterUpdateReply / onSymbolAppearanceUpdateReply } void InterfaceImpl::startReplayAppInternal() { const LtsSession::DdsConnectionParams connParams(m_data); // what's the difference? // LtsAppManager::LtsAppManager::getInstance()->createApp(static_cast(LtsSession::LtsSession::App::Situation), connParams); m_session->getSessionManager()->createSession(connParams, true, false /* no payloads! */); } bool InterfaceImpl::transferFilter(const Core::ReplayPartition &data) { if (m_requestHelper == nullptr) m_requestHelper = new LtsUtils::RequestHelper(this); // copy last filter from current session to replay: const int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId(); const QString context = m_session->workspaceId(); const QString replayContext = QStringLiteral("replay_%1").arg(data.id()); // AES: auto fOrig = m_fltAesIfc->aesFilterForOperator(operatorId, context); auto fReplay = m_fltAesIfc->aesFilterForOperator(operatorId, replayContext); // AesDisplayFilter fReplay->setFilterFromData(fOrig->filterToData()); auto cb1 = [this, fReplay]() { return m_fltFtc->aesFilterUpdateRequest(fReplay->filterToData(), this); }; m_requestHelper->addRequest(cb1); // SymbolAppearance: auto sOrig = m_fltParticipantIfc->symbolAppearanceForOperator(operatorId, context); auto sReplay = m_fltParticipantIfc->symbolAppearanceForOperator(operatorId, replayContext); sReplay->setSettings(sOrig->settings(), FilterManagement::SymbolAppearanceSettings::Part::All); auto cb2 = [this, sReplay]() { return m_fltFtc->symbolAppearanceUpdateRequest(sReplay->settingsToData(), this); }; m_requestHelper->addRequest(cb2); return m_requestHelper->startRequests(); } void InterfaceImpl::onAesFilterUpdateReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); // the last replay should trigger startReplayAppInternal to continue, but // give flt some time publish data (race condition) m_aesTransfered = true; if (m_aesTransfered && m_symbolAppearanceTransfered) QTimer::singleShot(2000, this, &InterfaceImpl::startReplayAppInternal); } void InterfaceImpl::onSymbolAppearanceUpdateReply(const Core::FunctionReplyObject &replyObject) { m_requestHelper->requestReply(replyObject); // the last replay should trigger startReplayAppInternal to continue, but // give flt some time publish data (race condition) m_symbolAppearanceTransfered = true; if (m_aesTransfered && m_symbolAppearanceTransfered) QTimer::singleShot(2000, this, &InterfaceImpl::startReplayAppInternal); } } // namespace SituationReplayManagement