/** * @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 #include #include #include #include #include #include #include #include #include #include #include #include /* * 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 sitMapIfc; if (!m_replayAppSession->getForeignGuiInterface(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 #"<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 srpIfc; if (!m_replayAppSession->getForeignGuiInterface(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 &session, const QPointer &replayAppSession, const std::shared_ptr &avmIfc, const std::shared_ptr &mrkIfc, const std::shared_ptr &fltParticipantIfc, const std::shared_ptr &fltAesIfc, const std::shared_ptr &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 srpIfc; std::shared_ptr sitMapIfc; if (!m_session->getDtc(m_mrkDtc)) WARNING_LOG(m_logger) << "!m_session->getDtc(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(srpIfc)) WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no srp, no replay in Show Details Dialog"; if (!replayAppSession->getForeignGuiInterface(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 (%2)").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(" (%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("")).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(""), attributeDetail.attributeTypeId); attributeValueText = tr(""); 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 (%2)").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(""), ProjectDataManagement::toString(static_cast(event->typeId()))); m_ui->lblEventType->setText(QStringLiteral("%1").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