Files
qt5-legatus-legacy/Lts/Plugins/Timeline/Gui/EventTimelineClassic/tln_show_details.cpp
T
2026-08-13 18:33:10 +02:00

522 lines
20 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Show Details Dialog
* $Id$
* $HeadURL$
* $Author$
* Created by Iuliana Ojog, SLSE, 2017-05-22
*/
#include "tln_show_details.h"
#include "ui_tln_show_details.h"
#include "tln_view_gui_plugin.h"
#include "detail_data.h"
#include "logger.h"
#include <LtsWidgets/lts_base.h>
#include <ngltools/ngltools_dtg.h>
#include <LtsTimelineClassic/Event.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <Services/ProjectDataManagement/pdm_translation.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <Plugins/MarkerManagement/Gui/Common/mrk_apply_filter.h>
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
/*
* NOTE:
*
* This Dialog uses foreign gui ifcs from a Session that is not ours!
* If we have the last shared_ptr to a foreign Session's foreign Ifc,
* and our Dialog gets deleted AFTER the foreign Session was killed,
* then we trigger the deletion of the dead foreign Ifc of a DEAD SESSION.
* So ifc shared_ptrs are fetched when needed and removed directly after use.
*
* Shared Pointers.
*
*/
namespace Timeline
{
ShowDetailsDialog::ShowDetailsDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_ui(new Ui::ShowDetailsDialog)
, m_logger(getLogger("ShowDetailsDialog"))
{
m_ui->setupUi(this);
setUnchangeable();
m_ui->debugWidget->hide();
connect(m_ui->pbStartReplay, &QPushButton::clicked,
this, &ShowDetailsDialog::slotStartReplay);
connect(m_ui->pbShowMarker, &QPushButton::clicked,
this, &ShowDetailsDialog::slotShowMarker);
connect(m_ui->pbPlayback, &QPushButton::clicked,
this, &ShowDetailsDialog::slotStartPlayback);
connect(m_ui->pbFocus, &QPushButton::clicked,
this, &ShowDetailsDialog::slotFocusOnMap);
m_ui->tbFocus->hide();
m_ui->tbMarker->hide();
m_ui->tbPlayback->hide();
m_ui->tbReplay->hide();
#ifndef LTS_DEBUG
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("Timeline.Debug")) == QVariant(true))
#endif
{
m_ui->debugWidget->show();
}
}
//------------------------------------------------------------------------------------------------------------------------
ShowDetailsDialog::~ShowDetailsDialog()
{
m_session = nullptr;
m_mrkDtc = nullptr;
delete m_ui;
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::retranslate()
{
translate(m_ui, m_eventType, false, tr("Event"));
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::slotFocusOnMap()
{
if (m_replayAppSession == nullptr)
{
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no replay app, no focus";
return;
}
std::shared_ptr<SituationMap::ForeignGuiInterface> sitMapIfc;
if (!m_replayAppSession->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(sitMapIfc))
{
WARNING_LOG(m_logger) << "no sitMapIfc, no focusing on replay in Show Details Dialog 1";
return;
}
if (!sitMapIfc)
{
WARNING_LOG(m_logger) << "no sitMapIfc, no focusing on replay in Show Details Dialog 2";
return;
}
if (m_event->typeId() != markerTypeId) // NOTE: marker events have their position stored in the map settings
{
if (!m_event->positionValid())
{
WARNING_LOG(m_logger) << "event has no valid position, skip focusOnMap";
return;
}
// x == lon ; y == lat
sitMapIfc->setCenterPoint(m_event->pos2d());
}
const QJsonObject root(m_event->detailData());
const QJsonValue mapSettings(root[QStringLiteral("MapSettings")]);
if (!mapSettings.isUndefined())
sitMapIfc->setOperatorMapSettings(mapSettings);
const QJsonValue filterSettings(root[QStringLiteral("Filter")]);
if (!filterSettings.isUndefined())
{
MarkerManagement::MarkerManagementApplyFilter applyFilter(m_replayAppSession, m_fltParticipantIfc, m_fltAesIfc, m_fltBuildingComponentIfc);
if (!applyFilter.applyFilter(filterSettings.toObject()))
{
WARNING_LOG(m_logger) << "filters from event #"<<m_event->uniqueId()<<" could not be applied";
return;
}
}
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::slotShowMarker()
{
m_mrkIfc->showMarker(m_event->uniqueId());
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::hasNameAndEndTime() const
{
QString dummy1;
qint64 dummy2;
return getStreamNameAndEndTime(dummy1, dummy2, true);
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::getStreamNameAndEndTime(QString &streamName, qint64 &endTime, bool silent) const
{
const QJsonObject root(m_event->detailData());
const QString _streamName = root[QStringLiteral("streamName")].toString(); // Lts/Services/ExerciseEventManagement/web_socket_avs.cpp:160
if (_streamName.isEmpty())
{
if (!silent)
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartVideo(): stream name is empty " << QJsonDocument(m_event->detailData()).toJson();
return false;
}
qint64 _endTime = root[QStringLiteral("endTime")].toDouble(0);
if (_endTime == 0 && !silent)
WARNING_LOG(m_logger) << "ShowDetailsDialog::slotStartPlayback: event " << m_event->uniqueId() << " has no end time!";
streamName = _streamName;
endTime = _endTime;
return true;
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::slotStartPlayback()
{
QString streamName;
qint64 endTime;
if (!getStreamNameAndEndTime(streamName, endTime))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot start playback as this event's informations are missing."));
return;
}
const bool isAudio = isAudioEventType(m_event->typeId());
if (!m_avmIfc->startAudioVideoPlayback(streamName, m_event->startTime(), isAudio))
new LtsWidgets::LtsMessageDialogNew(this, tr("Playback cannot be started because of an error. Please try again later."));
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::slotStartReplay()
{
if (m_replayAppSession == nullptr)
{
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartReplay: no replay app, no replay";
return;
}
std::shared_ptr<SituationReplay::ForeignGuiInterface> srpIfc;
if (!m_replayAppSession->getForeignGuiInterface<SituationReplay::ForeignGuiInterface>(srpIfc))
{
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartReplay: no srp, no replay in Show Details Dialog";
return;
}
srpIfc->startReplay(m_event->startTime() - (10 * 1000) /* TODO: offset? */); // TODO: endTime..
slotFocusOnMap();
}
//------------------------------------------------------------------------------------------------------------------------
void ShowDetailsDialog::setButtonDisabled(QPushButton *button, QToolButton *warningButton, const QString &reasonMessage, bool hide)
{
if (hide)
button->setVisible(false);
button->setEnabled(false);
button->setToolTip(reasonMessage);
warningButton->setToolTip(reasonMessage);
warningButton->show();
connect(warningButton, &QToolButton::clicked,
warningButton, [this, warningButton]()
{
LtsWidgets::LtsMessageDialog::showMessage(this, warningButton->toolTip());
});
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::isMarkerAudioVideo() const
{
const QJsonObject root(m_event->detailData());
return (root[QStringLiteral("IsAudioType")].toBool(false) || root[QStringLiteral("IsVideoType")].toBool(false));
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::isAvsCapable(const LtsTimelineClassic::Event *event)
{
const int eventType = event->typeId();
return isAvEventType(eventType) || eventType == Timeline::markerTypeId;
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::isHitEventType(int eventTypeId)
{
return (eventTypeId == ProjectDataManagement::EventType_def::Hit ||
eventTypeId == ProjectDataManagement::EventType_def::HitB ||
eventTypeId == ProjectDataManagement::EventType_def::HitBuilding ||
eventTypeId == ProjectDataManagement::EventType_def::HitC ||
eventTypeId == ProjectDataManagement::EventType_def::HitGasPipe ||
eventTypeId == ProjectDataManagement::EventType_def::HitEffectSimulation ||
eventTypeId == ProjectDataManagement::EventType_def::HitMine ||
eventTypeId == ProjectDataManagement::EventType_def::HitN);
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::isAvEventType(int eventTypeId)
{
return (isAudioEventType(eventTypeId) ||
eventTypeId == ProjectDataManagement::EventType_def::CameraVideo);
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::isAudioEventType(int eventTypeId)
{
return (eventTypeId == ProjectDataManagement::EventType_def::RadioCnr ||
eventTypeId == ProjectDataManagement::EventType_def::RadioTvc);
}
//------------------------------------------------------------------------------------------------------------------------
bool ShowDetailsDialog::init(DetailData *detailData, const LtsTimelineClassic::Event *event,
const QPointer<LtsSession::LtsSession> &session,
const QPointer<LtsSession::LtsSession> &replayAppSession,
const std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> &avmIfc,
const std::shared_ptr<MarkerManagement::ForeignGuiInterface> &mrkIfc,
const std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> &fltParticipantIfc,
const std::shared_ptr<FilterManagement::ForeignAesGuiInterface> &fltAesIfc,
const std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> &fltBuildingComponentIfc,
bool isTimelineApp,
QWidget *pseudoParent,
AudioVideoManagement::StreamNameMapping *streamNameMapping)
{
m_session = session;
//Q_ASSERT(streamNameMapping);
// m_srpIfc = srpIfc; << from replay app
// m_sitMapIfc = sitMapIfc; << from replay app
std::shared_ptr<SituationReplay::ForeignGuiInterface> srpIfc;
std::shared_ptr<SituationMap::ForeignGuiInterface> sitMapIfc;
if (!m_session->getDtc<MarkerManagement::DataInterface>(m_mrkDtc))
WARNING_LOG(m_logger) << "!m_session->getDtc<MarkerManagement::DataInterface>(m_mrkDtc)";
m_mrkDtc->enableMarker();
connect(m_mrkDtc.get(), &MarkerManagement::Interface::Dtc::markerChanged,
this, &ShowDetailsDialog::updateMarker);
if (replayAppSession != nullptr)
{
m_replayAppSession = replayAppSession;
connect(replayAppSession.data(), &LtsSession::LtsSession::destroyed,
this, [this]()
{
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("No map available."));
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Situation Replay App not started."));
});
if (!replayAppSession->getForeignGuiInterface<SituationReplay::ForeignGuiInterface>(srpIfc))
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no srp, no replay in Show Details Dialog";
if (!replayAppSession->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(sitMapIfc))
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no sitMapIfc, no focusing on replay in Show Details Dialog";
}
m_avmIfc = avmIfc;
m_mrkIfc = mrkIfc;
m_fltParticipantIfc = fltParticipantIfc;
m_fltAesIfc = fltAesIfc;
m_fltBuildingComponentIfc = fltBuildingComponentIfc;
m_streamNameMapping = streamNameMapping;
if (m_avmIfc == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no avm ifc given";
if (m_mrkIfc == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no mrk ifc given";
if (m_fltParticipantIfc == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt Part ifc given";
if (m_fltAesIfc == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt Aes ifc given";
if (m_fltBuildingComponentIfc == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt buildingComponent ifc given";
if (m_streamNameMapping == nullptr)
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no stream name mapping given";
m_event = event;
int eventTypeId = event->typeId();
// hide equipment id labels if event has no eq id
if (event->equipmentId() <= 0)
{
m_ui->lblEquipNo->hide();
m_ui->lblValueEquipNo->hide();
}
else
m_ui->lblValueEquipNo->setText(QString::number(event->equipmentId()));
connect(pseudoParent, &QWidget::destroyed, this, &ShowDetailsDialog::deleteLater);
QString eventTime;
if (m_logger.isDebugEnabled())
eventTime = QStringLiteral("%1 <font color='#aebac6'>(%2)</font>").arg(DTG::toStringMSec(event->startTime())).arg(event->startTime());
else
eventTime = DTG::toStringMSec(event->startTime());
m_ui->lblValueEventTime->setText(eventTime);
m_eventType = detailData->eventTypeLookup.getEventText(eventTypeId);
if (m_eventType.isEmpty())
m_eventType = tr("<unknown> (%1)").arg(eventTypeId);
if (sitMapIfc == nullptr || isTimelineApp)
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("No map available"), true);
else if (eventTypeId != markerTypeId && !m_event->positionValid()) // NOTE: markers get their position from the map settings !
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("Event has an invalid position and cannot be focused"));
if (srpIfc == nullptr)
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Situation Replay App not started."));
else if (sitMapIfc == nullptr)
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("This app has no map to focus this event on."));
else if (eventTypeId != markerTypeId && !m_event->positionValid()) // NOTE: markers get their position from the map settings !
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Event has an invalid position, cannot be focused and therefore has no replay capability."));
if (eventTypeId != markerTypeId)
setButtonDisabled(m_ui->pbShowMarker, m_ui->tbMarker, tr("This event is not a marker."), true);
else if (m_mrkIfc == nullptr)
setButtonDisabled(m_ui->pbShowMarker, m_ui->tbMarker, tr("This app has no marker interface available."), true);
if (!isAvsCapable(event))
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This event is not an audio/video type."), true);
else if (m_avmIfc == nullptr)
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This app has no audio/video interface available."), true);
else if (eventTypeId == Timeline::markerTypeId && !isMarkerAudioVideo())
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This marker event is not an audio / video type."), true);
else if (!hasNameAndEndTime())
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This event has missing informations about the playback."));
// Button im Ereignisfenster abhaengig vom Eventtyp ausblenden
if (isAvsCapable(event))
{
m_ui->pbFocus->hide();
m_ui->tbFocus->hide();
m_ui->pbStartReplay->hide();
m_ui->tbReplay->hide();
}
const DetailData::GetDetailDataResultList result = detailData->getDetailData(event);
QLocale locale; // uses system locale
for (const DetailData::GetDetailDataForAttributeResult &attributeDetail : result)
{
// do not add time again
if (detailData->attributeInterpreterLookup.getInterpreterType(attributeDetail.attributeTypeId) == DetailData::INTERPRETER_TYPE_TIME)
continue;
QString attributeTypeText;
QString attributeValueText;
if (attributeDetail.requestResult != DetailData::RequestResult::Okay)
{
if (attributeDetail.requestResult == DetailData::RequestResult::NoValueTranslationForAttribute) // attribute type valid, but no attribute value, but a attribute value id is given - show the id!
{
attributeTypeText = attributeDetail.attributeType;
attributeValueText = QStringLiteral("%1 (%2)").arg(tr("<unknown>")).arg(attributeDetail.attributeValueId);
}
else if (attributeDetail.requestResult == DetailData::RequestResult::InvalidAttributeType)
{
// an attribute which we don't handle, it's fine
DEBUG_LOG(m_logger) << "Unhandled attribute " << attributeDetail.attributeTypeId << " - skipping";
continue;
}
else // everything went wrong, only show unknown ids for both key and value
{
attributeTypeText = QStringLiteral("%1 (%2)").arg(tr("<unknown>"), attributeDetail.attributeTypeId);
attributeValueText = tr("<type unknown>");
WARNING_LOG(m_logger) << "getDetailData failed with message id " << (int)attributeDetail.requestResult << " for attribute " << attributeDetail.attributeTypeId;
continue; // do not add unknown types
}
}
else // everything worked fine:
{
attributeTypeText = attributeDetail.attributeType;
// user readability
bool isNumber = false;
qint64 attributeValueAsNumber = attributeValueText.toLongLong(&isNumber);
if (isNumber)
attributeValueText = locale.toString(attributeValueAsNumber);
if (m_logger.isDebugEnabled())
attributeValueText = QStringLiteral("%1 <font color='#aebac6'>(%2)</font>").arg(attributeDetail.attributeValue).arg(attributeDetail.attributeValueId);
else
attributeValueText = attributeDetail.attributeValue;
}
QString attributeType(attributeDetail.attributeTypeId);
// leave some attributes out ...
int eventType = event->typeId();
if (isAudioEventType(eventType))
{
if (attributeType == QStringLiteral("MainStructureElementId"))
continue;
}
else if (isHitEventType(eventType))
{
if (attributeType == QStringLiteral("OriginatorType"))
continue;
}
if (attributeType == QStringLiteral("GearId")) // never show gear id
continue;
QLabel *attributeValueTextLabel = new QLabel(attributeValueText);
DEBUG_LOG(m_logger) << "attributeValueText=" << attributeValueText;
attributeValueTextLabel->setTextInteractionFlags(attributeValueTextLabel->textInteractionFlags() | Qt::TextInteractionFlag::TextSelectableByMouse);
DEBUG_LOG(m_logger) << "attributeTypeText=" << attributeTypeText
<< " attributeValueTextLabel=" << attributeValueTextLabel;
m_ui->formLayout->addRow(new QLabel(attributeTypeText), attributeValueTextLabel);
}
if (m_eventType.isEmpty())
m_eventType = QStringLiteral("%1 (%2)").arg(tr("<unknown>"), ProjectDataManagement::toString(static_cast<ProjectDataManagement::EventType::type>(event->typeId())));
m_ui->lblEventType->setText(QStringLiteral("<b>%1</b>").arg(m_eventType));
m_ui->pteDetailDataTest->setPlainText(QString::fromUtf8(QJsonDocument(event->detailData()).toJson()));
QString pos(QStringLiteral("x: %1 - y: %2 - z: %3").arg(m_event->position().x()).arg(m_event->position().y()).arg(m_event->position().z()));
m_ui->lblPos->setText(pos);
return true;
}
void ShowDetailsDialog::updateMarker()
{
DEBUG_LOG(m_logger) << "ShowDetailsDialog::updateMarker";
}
//------------------------------------------------------------------------------------------------------------------------
} // namespace Timeline