293 lines
9.4 KiB
C++
Executable File
293 lines
9.4 KiB
C++
Executable File
/**
|
|
* @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 <LtsSession/lts_session.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <LtsSession/lts_session_manager.h>
|
|
#include <LtsUtilsCore/await.h>
|
|
#include <LtsUtilsGuiDds/request_helper.h>
|
|
#include <LtsWidgets/lts_global_wait_dialog.h>
|
|
#include <LtsWidgets/lts_wait_dialog.h>
|
|
#include <LtsAppManager/lts_app_manager.h>
|
|
|
|
#include <FilterManagement/flt_data_plugin_aes_display_filter.h>
|
|
#include <FilterManagement/flt_symbol_appearance_settings.h>
|
|
#include <Services/SituationReplayManagement/srm_operator_rights.h>
|
|
|
|
#include <QTimer>
|
|
#include <QDebug>
|
|
|
|
|
|
namespace SituationReplayManagement
|
|
{
|
|
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.Srm.ReplayManagement"))
|
|
, m_requestHelper(nullptr)
|
|
{}
|
|
|
|
InterfaceImpl::~InterfaceImpl()
|
|
{
|
|
|
|
}
|
|
|
|
bool InterfaceImpl::fetchInterfaces()
|
|
{
|
|
if (!m_session->getDtc<DataInterface>(m_coreDtc))
|
|
return false;
|
|
if (!m_session->getForeignDataInterface<DataInterface>(m_sitRepIfc))
|
|
return false;
|
|
|
|
if (!m_session->getForeignGuiInterface<FilterManagement::ForeignFltParticipantGuiInterface>(m_fltParticipantIfc))
|
|
{
|
|
DEBUG_LOG(m_logger) << "getForeignGuiInterface for Filter Management Participant Gui failed.";
|
|
return false;
|
|
}
|
|
if (!m_session->getForeignGuiInterface<FilterManagement::ForeignAesGuiInterface>(m_fltAesIfc))
|
|
{
|
|
DEBUG_LOG(m_logger) << "getForeignGuiInterface for Filter Management Aes Gui failed.";
|
|
return false;
|
|
}
|
|
if (!m_session->getFtc<FilterManagement::DataInterface>(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<LtsWidgets::PluginData> InterfaceImpl::getActions()
|
|
{
|
|
QVector<LtsWidgets::PluginData> 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<LtsWidgets::LtsWaitDialog> _(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<int>(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
|