- training_area_telegrams.cpp: Fixed QJsonObject initializer syntax (Qt6 requires {{}} not ({}))
- training_area_telegrams.cpp: Fixed fromJson() methods to access m_* members directly
- training_area_telegrams.cpp: Fixed brace mismatches in multiple toJson() methods
- training_area_telegrams.h: Changed Header struct to public members for consistency
- tx_mixin.cpp: Fixed getEquipmentNumber() template for direct member access
- lts_coordinate.cpp: Added missing #include <iomanip>
- MIGRATION_STATUS.md: Added migration progress tracking document
C++17 constraint enforced due to RTI Connext DDS 7.7.0 incompatibility with C++20+
Build status: BUILD_RTI=OFF successful (0 errors, warnings only)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1078 lines
30 KiB
C++
Executable File
1078 lines
30 KiB
C++
Executable File
|
|
|
|
|
|
#include "tln_dialog.h"
|
|
#include "ui_tln_dialog.h"
|
|
#include "tln_dialog_model.h"
|
|
#include "tln_cache_dialog.h"
|
|
#include "tln_show_details.h"
|
|
#include "tln_event_list.h"
|
|
#include "tln_legend.h"
|
|
#include "detail_data.h"
|
|
#include "excon_filter.h"
|
|
#include "logger.h"
|
|
#include "EventFilter/FilterWindow.h"
|
|
|
|
#include <LtsSession/lts_session_manager.h>
|
|
#include <LtsUtilsSettings/settings.h>
|
|
#include <LtsAppManager/lts_app_manager.h>
|
|
#include <LtsPluginManager/lts_plugin_manager.h>
|
|
#include <LtsSession/lts_session_data.h>
|
|
#include <LtsSession/lts_session.h>
|
|
#include <LtsWidgets/lts_global_wait_dialog.h>
|
|
#include <LtsTimelineClassic/EventGraphic.h>
|
|
#include <LtsTimelineClassic/EventTools.h>
|
|
#include <ngltools/ngltools_dtg.h>
|
|
|
|
#include <QtWidgets/QDialog>
|
|
#include <QtWidgets/QPushButton>
|
|
#include <QtWidgets/QLineEdit>
|
|
#include <QtWidgets/QTextEdit>
|
|
#include <QtWidgets/QFormLayout>
|
|
#include <QtWidgets/QSpinBox>
|
|
#include <QtCore/QJsonDocument>
|
|
#include <QtCore/QJsonObject>
|
|
#include <QtCore/QJsonArray>
|
|
#include <QJsonParseError>
|
|
|
|
#include <QtCore/QDebug>
|
|
|
|
using namespace LtsTimelineClassic;
|
|
|
|
namespace Timeline
|
|
{
|
|
|
|
TimelineViewDialog::TimelineViewDialog(const QString &menuGroup, const LtsWidgets::ButtonCombination &buttonCombo, bool isMain, QWidget *parent)
|
|
: LtsWidgets::LtsDialog(parent, buttonCombo, !isMain)
|
|
, m_ui(new Ui::TimelineViewDialog)
|
|
, m_menuGroup(menuGroup)
|
|
, m_model(new DDSTimelineModel(this))
|
|
, m_detailData(nullptr)
|
|
, m_filterWindow(nullptr)
|
|
, m_eventListDialog(nullptr)
|
|
, m_allEventsListDialog(nullptr)
|
|
, m_session(nullptr)
|
|
, m_requestHelper(new LtsUtils::RequestHelper(this))
|
|
, m_streamNameMapping(nullptr)
|
|
, m_rangeChanged(false)
|
|
, m_loadingCount(0)
|
|
, m_armed(false)
|
|
, m_exerciseStart(0)
|
|
, m_legendDialog(nullptr)
|
|
{
|
|
m_ui->setupUi(this);
|
|
|
|
#ifndef LTS_DEBUG
|
|
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("Timeline.DebugWidget")) != QVariant(true))
|
|
{
|
|
m_ui->debugWidget->hide();
|
|
m_ui->widget->hideDebugWidget();
|
|
}
|
|
#endif
|
|
|
|
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &TimelineViewDialog::slotShowFiltersDialog);
|
|
m_buttonBox->connectButton(LtsWidgets::DialogButton::Show, this, &TimelineViewDialog::slotShowLegend);
|
|
m_buttonBox->connectButton(LtsWidgets::DialogButton::Import, this, &TimelineViewDialog::slotStartReplaySituation);
|
|
|
|
connect(m_ui->pbDebugCreateFakeEvent, &QPushButton::clicked,
|
|
this, &TimelineViewDialog::slotDebugCreateFakeEvent);
|
|
|
|
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
|
|
const bool enableListEvents = ps->value(QStringLiteral("tln"),
|
|
QStringLiteral("enableListEvents")).toBool();
|
|
|
|
if (enableListEvents)
|
|
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &TimelineViewDialog::loadAllEvents);
|
|
|
|
connect(m_ui->widget, &TimelineWidget::signalZoomChanged,
|
|
this, [this]()
|
|
{
|
|
m_model->invalidateTimeline();
|
|
});
|
|
|
|
connect(this, &TimelineViewDialog::signalWaitForReady,
|
|
this, &TimelineViewDialog::slotWaitForReady, Qt::QueuedConnection);
|
|
|
|
connect(m_ui->widget, &TimelineWidget::signalEventAction,
|
|
this, &TimelineViewDialog::showDetailsAction);
|
|
|
|
setOnlineHelpFilename(QStringLiteral("Timeline-Application"));
|
|
}
|
|
|
|
|
|
TimelineViewDialog::~TimelineViewDialog()
|
|
{
|
|
if (m_allEventsListDialog)
|
|
{
|
|
delete m_allEventsListDialog.data();
|
|
m_allEventsListDialog = nullptr;
|
|
}
|
|
|
|
if (m_eventListDialog)
|
|
{
|
|
delete m_eventListDialog.data();
|
|
m_eventListDialog = nullptr;
|
|
}
|
|
|
|
delete m_ui;
|
|
delete m_filterWindow;
|
|
delete m_legendDialog;
|
|
|
|
EventTools::s_inUse = false;
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotDebugCreateFakeEvent()
|
|
{
|
|
QFormLayout *fl = new QFormLayout;
|
|
|
|
QLineEdit *typeIdWidget = new QLineEdit;
|
|
typeIdWidget->setText(QStringLiteral("8"));
|
|
fl->addRow(QStringLiteral("typeId"), typeIdWidget);
|
|
|
|
QLineEdit *startWidget = new QLineEdit;
|
|
startWidget->setText(QStringLiteral("1571141793040"));
|
|
fl->addRow(QStringLiteral("start"), startWidget);
|
|
|
|
QSpinBox *sb = new QSpinBox;
|
|
sb->setMaximum(INT_MAX);
|
|
sb->setValue(26);
|
|
fl->addRow(QStringLiteral("duration [s]"), sb);
|
|
|
|
QTextEdit *te = new QTextEdit;
|
|
te->setPlainText(QStringLiteral("{ \"streamName\": \"00003\", \"endTime\": 1571141819620 }"));
|
|
fl->addRow(QStringLiteral("detail"), te);
|
|
|
|
QPushButton *goBtn = new QPushButton(QStringLiteral("Go"));
|
|
connect(goBtn, &QPushButton::clicked, this, [this, typeIdWidget, startWidget, sb, te]()
|
|
{
|
|
bool k = false;
|
|
int typeId = typeIdWidget->text().toInt(&k);
|
|
if (!k)
|
|
{
|
|
new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("TypeId invalid"));
|
|
return;
|
|
}
|
|
|
|
qint64 start = startWidget->text().toLongLong(&k);
|
|
if (!k)
|
|
{
|
|
new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("start invalid"));
|
|
return;
|
|
}
|
|
|
|
qint64 end = start + (sb->value() * 1000);
|
|
|
|
QJsonParseError error;
|
|
const QJsonObject root(QJsonDocument::fromJson(te->toPlainText().toUtf8(), &error).object());
|
|
|
|
if (error.error != QJsonParseError::NoError)
|
|
{
|
|
new LtsWidgets::LtsMessageDialogNew(this, QStringLiteral("Detail data json invalid: '%1' at offset %2").arg(error.errorString()).arg(error.offset));
|
|
return;
|
|
}
|
|
|
|
static int uniqueId = 9999999;
|
|
Event *e = new Event(uniqueId++, typeId, start, end, -1, -1, 1, { QStringLiteral("none") }, LtsTimelineClassic::Event::drawCustomEventGraphicRect, {}, root, -1);
|
|
|
|
showDetails({e});
|
|
});
|
|
|
|
|
|
fl->addRow({}, goBtn);
|
|
|
|
QDialog *d = new QDialog(this);
|
|
d->setLayout(fl);
|
|
d->show();
|
|
d->activateWindow();
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::aboutToClose()
|
|
{
|
|
if (m_allEventsListDialog)
|
|
{
|
|
delete m_allEventsListDialog.data();
|
|
m_allEventsListDialog = nullptr;
|
|
}
|
|
|
|
if (m_eventListDialog)
|
|
{
|
|
delete m_eventListDialog.data();
|
|
m_eventListDialog = nullptr;
|
|
}
|
|
|
|
if (m_replayApp != nullptr)
|
|
m_replayApp->deleteLater();
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::retranslate()
|
|
{
|
|
translate(m_ui, tr("Timeline"));
|
|
m_detailData->populate();
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Filters"));
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Show)->setText(tr("Legend", "Deutsch: Legende (erklärende Ergänzung zu einer Grafik)"));
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("List events"));
|
|
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Import)->setText(tr("Start Situation Replay App"));
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Import)->setToolTip(tr("Replays started from the Show Details dialog will play in the Situation Replay App."));
|
|
}
|
|
|
|
|
|
bool TimelineViewDialog::init(const std::shared_ptr<TimeLineManagement::ForeignDataInterface> &eemForeign,
|
|
const std::shared_ptr<MarkerManagement::Interface::Dtc> &mrkDtc,
|
|
const std::shared_ptr<ExerciseManagement::Interface::Dtc> &exmDtc,
|
|
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
|
|
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
|
|
const std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> &ppmInfoIfc,
|
|
const std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> &avmIfc,
|
|
const std::shared_ptr<MarkerManagement::ForeignGuiInterface> &mrkIfc,
|
|
const std::shared_ptr<SituationReplayManagement::ForeignDataInterface> &srmDataIfc,
|
|
const std::shared_ptr<Core::Interface::Dtc> &coreDtc,
|
|
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
|
|
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
|
|
const std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> &fltParticipantIfc,
|
|
const std::shared_ptr<FilterManagement::ForeignAesGuiInterface> &fltAesIfc,
|
|
const std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> &fltBuildingComponentIfc,
|
|
LtsSession::LtsSession *session,
|
|
AudioVideoManagement::StreamNameMapping *streamNameMapping)
|
|
{
|
|
if (EventTools::s_inUse)
|
|
{
|
|
new LtsWidgets::LtsMessageDialogNew(session->baseLayout(), tr("Cannot open timeline as there is already another timeline instance running in the application."), tr("Another timeline instance already in use"));
|
|
return false;
|
|
}
|
|
|
|
EventTools::s_inUse = true;
|
|
|
|
m_session = session;
|
|
m_exmDtc = exmDtc;
|
|
m_flmIfc = flmIfc;
|
|
m_ppmDtc = ppmDtc;
|
|
m_ppmInfoIfc = ppmInfoIfc;
|
|
m_avmIfc = avmIfc;
|
|
m_mrkIfc = mrkIfc;
|
|
m_srmDataIfc = srmDataIfc;
|
|
m_coreDtc = coreDtc;
|
|
m_pdmDtc = pdmDtc;
|
|
m_ismDtc = ismDtc;
|
|
m_mrkDtc = mrkDtc;
|
|
m_fltParticipantIfc = fltParticipantIfc;
|
|
m_fltAesIfc = fltAesIfc;
|
|
m_fltBuildingComponentIfc = fltBuildingComponentIfc;
|
|
m_streamNameMapping = streamNameMapping;
|
|
|
|
if (m_coreDtc == nullptr || m_srmDataIfc == nullptr)
|
|
{
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, false);
|
|
m_buttonBox->getButton(LtsWidgets::DialogButton::Import)->setToolTip(tr("Required interfaces missing for starting the Situation Replay App."));
|
|
}
|
|
|
|
m_detailData = new DetailData(session, this);
|
|
|
|
if (!m_model->init(eemForeign, mrkDtc, exmDtc, ppmDtc, pdmDtc, ismDtc, session, m_detailData, m_streamNameMapping))
|
|
{
|
|
ERROR_LOG(m_logger) << "model init failed";
|
|
return false;
|
|
}
|
|
|
|
m_ui->widget->setTimelineModel(m_model);
|
|
|
|
|
|
connect(m_model, &DDSTimelineModel::signalRebuildTimelineKnownRanges,
|
|
this, [this]()
|
|
{
|
|
m_ui->widget->knownRangesChanged(m_model->getKnownRanges());
|
|
|
|
emit m_model->dataChanged(QModelIndex(), QModelIndex());
|
|
});
|
|
|
|
connect(m_model, &DDSTimelineModel::signalLoading,
|
|
this, &TimelineViewDialog::slotLoading);
|
|
connect(m_model, &DDSTimelineModel::signalLoadingDone,
|
|
this, &TimelineViewDialog::slotLoadingDone);
|
|
|
|
connect(this, &TimelineViewDialog::signalInitEventList,
|
|
this, [this]()
|
|
{
|
|
if (m_allEventsListDialog)
|
|
{
|
|
|
|
EventList visibleEvents = setFilter(m_detailData, m_model->getRootItem()->getFullEventList(true, true), m_filter, this, true, false);
|
|
m_allEventsListDialog->reInitEventList(visibleEvents, m_ui->widget->getRangeMinimum(), m_ui->widget->getRangeMaximum());
|
|
}
|
|
});
|
|
|
|
|
|
QTimer *armTimer = new QTimer(this);
|
|
armTimer->setInterval(750);
|
|
connect(armTimer, &QTimer::timeout,
|
|
this, [this]()
|
|
{
|
|
if (!m_rangeChanged)
|
|
return;
|
|
m_rangeChanged = false;
|
|
|
|
qint64 rangeMin = m_ui->widget->getRangeMinimum();
|
|
qint64 rangeMax = m_ui->widget->getRangeMaximum();
|
|
|
|
if (rangeMin > rangeMax)
|
|
return;
|
|
|
|
qint64 now = m_session->partitionTime();
|
|
|
|
if (rangeMin >= now)
|
|
return;
|
|
|
|
if (rangeMax >= now)
|
|
{
|
|
rangeMax = m_session->partitionTime() -1;
|
|
|
|
}
|
|
|
|
|
|
m_model->getEvents(rangeMin, rangeMax);
|
|
});
|
|
|
|
#ifndef LTS_DEBUG
|
|
m_armed = true;
|
|
armTimer->start();
|
|
#endif
|
|
|
|
|
|
#ifndef LTS_DEBUG
|
|
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("Timeline.DebugWidget")) == QVariant(true))
|
|
#endif
|
|
{
|
|
|
|
QTimer *tCursor = new QTimer(this);
|
|
tCursor->setInterval(500);
|
|
connect(tCursor, &QTimer::timeout,
|
|
this, [this]()
|
|
{
|
|
qint64 cursorTime = EventTools::getEventTime(m_ui->widget->mapFromGlobal(QCursor::pos()).x());
|
|
m_ui->lblCursorTime->setText(QStringLiteral("%1 (%2)").arg(QDateTime::fromMSecsSinceEpoch(cursorTime).toString()).arg(cursorTime));
|
|
});
|
|
tCursor->start();
|
|
|
|
|
|
|
|
QTimer *tDraws = new QTimer(this);
|
|
tDraws->setInterval(1000);
|
|
connect(tDraws, &QTimer::timeout,
|
|
this, [this]()
|
|
{
|
|
int paints = EventTools::s_test;
|
|
EventTools::s_test = 0;
|
|
m_ui->label_8->setText(QStringLiteral("%1 draw(s) per second").arg(paints));
|
|
});
|
|
tDraws->start();
|
|
|
|
|
|
|
|
connect(m_ui->cbFake, &QCheckBox::toggled,
|
|
this, [this](bool toggled)
|
|
{
|
|
qWarning() << "fake toggled? " << toggled;
|
|
m_model->setCreateFakeEvents(toggled);
|
|
});
|
|
|
|
|
|
|
|
connect(m_ui->widget, &TimelineWidget::signalArm,
|
|
this, [this, armTimer](bool arm)
|
|
{
|
|
m_armed = arm;
|
|
if (arm)
|
|
armTimer->start();
|
|
else
|
|
armTimer->stop();
|
|
});
|
|
|
|
|
|
|
|
connect(m_ui->pbShowCache, &QPushButton::clicked,
|
|
this, [this]()
|
|
{
|
|
TimelineCacheDialog *cacheDialog = new TimelineCacheDialog(this);
|
|
|
|
connect(cacheDialog, &TimelineCacheDialog::signalUncache,
|
|
this, [this](int )
|
|
{
|
|
|
|
|
|
WARNING_LOG(m_logger) << "reimpl me!!";
|
|
});
|
|
|
|
cacheDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
|
cacheDialog->init(m_model->cachedEvents(), m_model->liveCache());
|
|
cacheDialog->show();
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect(m_ui->widget, &TimelineWidget::signalRangeChanged,
|
|
this, [this, armTimer]()
|
|
{
|
|
|
|
|
|
if (!m_model->hasActiveEventTypes())
|
|
{
|
|
DEBUG_LOG(m_logger) << "range changed, but no active event types! not arming timer..";
|
|
return;
|
|
}
|
|
|
|
if (m_armed)
|
|
armTimer->start();
|
|
|
|
m_rangeChanged = true;
|
|
});
|
|
|
|
|
|
|
|
connect(m_session, &LtsSession::LtsSession::partitionTimeChanged,
|
|
this, [this](qint64 )
|
|
{
|
|
#ifdef LTS_DEBUG
|
|
if (m_ui->cbUpdate->isChecked())
|
|
#endif
|
|
updateRange();
|
|
});
|
|
|
|
|
|
|
|
updateRange();
|
|
m_ui->widget->setPos(m_session->partitionTime());
|
|
|
|
connect(m_ui->sbSpan, &QScrollBar::valueChanged,
|
|
this, &TimelineViewDialog::slotSpanChanged);
|
|
|
|
connect(m_ui->pbLive, &QPushButton::clicked,
|
|
this, [this]()
|
|
{
|
|
updateRange(true );
|
|
});
|
|
|
|
m_exerciseStart = m_exmDtc->exercise(m_session->exerciseId()).beginTime();
|
|
|
|
if (m_exerciseStart < 1)
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(m_session->baseLayout(), tr("Exercise data not available or exercise not started yet."), tr("Cannot open timeline"));
|
|
ERROR_LOG(m_logger) << "exercise data not available - exercise start: " << m_exerciseStart;
|
|
return false;
|
|
}
|
|
|
|
{
|
|
|
|
QSignalBlocker block(m_ui->sbSpan);
|
|
(void)block;
|
|
updateRange(true );
|
|
}
|
|
|
|
m_ui->widget->setMaxPos();
|
|
|
|
|
|
|
|
m_ui->widget->setEnabled(false);
|
|
m_ui->sbSpan->setEnabled(false);
|
|
m_ui->pbLive->setEnabled(false);
|
|
|
|
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->wait();
|
|
emit signalWaitForReady();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotSpanChanged()
|
|
{
|
|
qint64 end = currentSpanTime();
|
|
qint64 start = end - (8 * 60 * 60 * 1000);
|
|
m_model->setTimeRange(start, end);
|
|
|
|
m_ui->lbStartTime->setText(DTG::toStringMSec(start));
|
|
m_ui->lbEndTime->setText(DTG::toStringMSec(end));
|
|
|
|
bool live = (m_ui->sbSpan->value() == m_ui->sbSpan->maximum());
|
|
|
|
m_model->setLive(live);
|
|
m_ui->widget->slotUpdateTimeline();
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotLoading()
|
|
{
|
|
#ifdef LTS_DEBUG
|
|
m_ui->lblStartTime->setStyleSheet(QLatin1String("background-color: green;"));
|
|
m_ui->lblEndTime->setStyleSheet(QLatin1String("background-color: green;"));
|
|
#endif
|
|
m_loadingCount++;
|
|
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotLoadingDone()
|
|
{
|
|
if (m_loadingCount > 0)
|
|
m_loadingCount--;
|
|
#ifdef LTS_DEBUG
|
|
if (m_loadingCount == 0)
|
|
{
|
|
m_ui->lblStartTime->setStyleSheet(QString());
|
|
m_ui->lblEndTime->setStyleSheet(QString());
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
emit signalInitEventList();
|
|
}
|
|
|
|
|
|
qint64 TimelineViewDialog::currentSpanTime() const
|
|
{
|
|
qint64 value = m_ui->sbSpan->value();
|
|
value *= 1000;
|
|
|
|
return value;
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::updateRange(bool initial)
|
|
{
|
|
qint64 start = m_exerciseStart;
|
|
qint64 partitionTime = m_session->partitionTime();
|
|
qint64 now = partitionTime;
|
|
|
|
if (now < 1)
|
|
now = start;
|
|
if (now == 0)
|
|
return;
|
|
|
|
now = (now / 1000);
|
|
|
|
bool liveSpan = (m_ui->sbSpan->value() == m_ui->sbSpan->maximum());
|
|
|
|
m_ui->sbSpan->setMinimum(start / 1000);
|
|
m_ui->sbSpan->setMaximum(now);
|
|
|
|
if (initial || liveSpan)
|
|
{
|
|
QSignalBlocker block(m_ui->sbSpan);
|
|
(void)block;
|
|
m_ui->sbSpan->setValue(now);
|
|
}
|
|
|
|
m_ui->widget->setLiveTime(partitionTime);
|
|
slotSpanChanged();
|
|
|
|
|
|
bool liveRange = (m_ui->widget->getPos() >= m_ui->widget->getMaxPos() - 1);
|
|
|
|
|
|
|
|
if (initial || liveRange)
|
|
{
|
|
|
|
m_ui->widget->setPos(EventTools::getTimelineMax());
|
|
}
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotStartReplaySituation()
|
|
{
|
|
if (m_replayApp != nullptr)
|
|
return;
|
|
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, false);
|
|
|
|
if (m_requestHelper->startSingleRequest([&]()
|
|
{
|
|
|
|
return m_srmDataIfc->replayPartitionCreateRequest(m_session->exerciseId(),
|
|
LtsSessionData::LtsSessionData::getInstance()->getWorkstationId(),
|
|
LtsSessionData::LtsSessionData::getInstance()->getOperatorId(),
|
|
Core::ReplayType::SituationData,
|
|
this);
|
|
}))
|
|
{
|
|
Core::ReplayPartition rp;
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
|
|
|
|
|
|
rp = m_coreDtc->replayPartition(m_requestHelper->getRepliedId());
|
|
|
|
if (rp.id() > 0)
|
|
break;
|
|
}
|
|
|
|
if (rp.id() == 0)
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error trying to create a replay session in stage 1."));
|
|
WARNING_LOG(m_logger) << "[timeout] Error while trying to create a replay session: domainId: " << m_session->domainId() <<
|
|
" - replay partition does not exist - replay id: " << m_requestHelper->getRepliedId() <<
|
|
" - url " << m_session->tcpConnectionUrl().toString();
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LtsSession::DdsConnectionParams connParams(rp);
|
|
m_replayApp = LtsAppManager::LtsAppManager::getInstance()->createApp(LtsAppDescriptor::App::Situation, connParams);
|
|
|
|
if (m_replayApp == nullptr)
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error trying to create a replay session in stage 2."));
|
|
WARNING_LOG(m_logger) << "Error while trying to create a replay session: domainId: " << m_session->domainId() <<
|
|
" - partition create reply (failed) - replay id: " << m_requestHelper->getRepliedId() <<
|
|
" - url: " << m_session->tcpConnectionUrl().toString();
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
connect(m_replayApp->m_sessionManager, &LtsSession::LtsSessionManager::signalInitializationFinished,
|
|
this, [this, rp]()
|
|
{
|
|
LtsSession::LtsSession *replayAppSession = m_replayApp->m_sessionManager->getSession(IDL::PartitionType::Replay, rp.id());
|
|
|
|
if (replayAppSession == nullptr)
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error trying to create a replay session in stage 4."));
|
|
return;
|
|
}
|
|
|
|
m_replayAppSession = replayAppSession;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
connect(m_replayApp.data(), &LtsPluginManager::LtsPluginManager::destroyed,
|
|
this, [this]()
|
|
{
|
|
|
|
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
|
|
});
|
|
});
|
|
|
|
LtsSession::LtsSession *replayAppSession = m_replayApp->m_sessionManager->getSession(IDL::PartitionType::Replay, rp.id());
|
|
|
|
|
|
auto fn = [this, replayAppSession]()
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error trying to create a replay session in stage 3."));
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
|
|
return;
|
|
};
|
|
|
|
if (replayAppSession->isInitializationDone())
|
|
fn();
|
|
else
|
|
connect(replayAppSession, &LtsSession::LtsSession::signalDoneInitializingSession,
|
|
this, fn);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Error trying to create a replay session."));
|
|
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Import, true);
|
|
}
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotEventTypesChanged(QSet<int> activeEventTypeIds)
|
|
{
|
|
if (m_filterWindow != nullptr && m_filterWindow->hasUnsavedChanges())
|
|
{
|
|
new LtsWidgets::LtsMessageDialogNew(this, tr("You have unsaved filters in Timeline's Filter dialog. Please save or discard them before you add or remove active events in Timeline's Legend dialog."), tr("Unsaved filters"));
|
|
return;
|
|
}
|
|
|
|
if (m_model->activeEventTypeIds().contains(markerTypeId))
|
|
activeEventTypeIds.insert(markerTypeId);
|
|
|
|
if (m_legendDialog != nullptr)
|
|
m_legendDialog->__unchange__();
|
|
|
|
setTimelineUsable(!activeEventTypeIds.isEmpty());
|
|
|
|
QSet<int> newActiveEventTypesIds(activeEventTypeIds - m_model->activeEventTypeIds());
|
|
|
|
|
|
m_model->setActiveEventTypeIds(activeEventTypeIds);
|
|
updateFiltersByActiveEventTypes();
|
|
|
|
if (!newActiveEventTypesIds.isEmpty())
|
|
m_model->getAllEventsOfType(newActiveEventTypesIds);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotShowLegend()
|
|
{
|
|
QString timelineLegendDialogIdent(QStringLiteral("Timeline.Legend"));
|
|
auto layoutArea = LtsWidgets::LayoutArea::eInfoTab;
|
|
|
|
if (m_legendDialog != nullptr)
|
|
{
|
|
focusDialog(m_menuGroup, timelineLegendDialogIdent, layoutArea);
|
|
return;
|
|
}
|
|
|
|
m_legendDialog = new TimelineLegendDialog;
|
|
|
|
connect(m_legendDialog, &TimelineLegendDialog::destroyed,
|
|
this, [this]()
|
|
{
|
|
if (static_cast<QWidget *>(sender()) == m_legendDialog)
|
|
m_legendDialog = nullptr;
|
|
});
|
|
|
|
connect(m_legendDialog, &TimelineLegendDialog::signalEventTypesChanged,
|
|
this, &TimelineViewDialog::slotEventTypesChanged);
|
|
|
|
if (!m_legendDialog->init(m_model, m_model->activeEventTypeIds()))
|
|
{
|
|
m_legendDialog->deleteLater();
|
|
m_legendDialog = nullptr;
|
|
return;
|
|
}
|
|
|
|
m_session->addWidget(m_legendDialog, m_menuGroup, timelineLegendDialogIdent, layoutArea);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotShowFiltersDialog()
|
|
{
|
|
if (m_detailData == nullptr)
|
|
return;
|
|
|
|
if (m_filterWindow != nullptr)
|
|
{
|
|
focusDialog(m_menuGroup, QStringLiteral("timelineFilterDialog"), LtsWidgets::LayoutArea::eDialogTab);
|
|
return;
|
|
}
|
|
|
|
m_filterWindow = new FilterWindow(m_detailData, m_flmIfc, m_session, this);
|
|
|
|
connect(m_filterWindow, &FilterWindow::signalShowEvents,
|
|
this, &TimelineViewDialog::slotShowEvents);
|
|
|
|
connect(m_filterWindow, &FilterWindow::signalApplyFilter,
|
|
this, &TimelineViewDialog::slotApplyFilter);
|
|
|
|
connect(m_filterWindow, &FilterWindow::destroyed,
|
|
this, [this]()
|
|
{
|
|
if (sender() == static_cast<QObject *>(m_filterWindow))
|
|
m_filterWindow = nullptr;
|
|
});
|
|
|
|
m_filterWindow->loadFilters(m_filter);
|
|
|
|
addDialog(m_filterWindow, m_menuGroup, QStringLiteral("timelineFilterDialog"));
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotShowEvents(const QJsonArray &filter)
|
|
{
|
|
EventList visibleEvents = setFilter(m_detailData, m_model->getRootItem()->getFullEventList(true, true), filter, this, true , false );
|
|
if (visibleEvents.isEmpty())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This filter has no results"), tr("No Events found"));
|
|
return;
|
|
}
|
|
|
|
showDetails(visibleEvents);
|
|
}
|
|
|
|
void TimelineViewDialog::loadAllEvents()
|
|
{
|
|
LtsTimelineClassic::EventList visibleEvents = setFilter(m_detailData, m_model->getRootItem()->getFullEventList(true, true), m_filter, this, true , false );
|
|
|
|
qint64 endTime = m_ui->widget->getRangeMaximum();
|
|
qint64 startTime = m_ui->widget->getRangeMinimum();
|
|
LtsTimelineClassic::EventList newEventList;
|
|
|
|
for (auto i = visibleEvents.constBegin(); i != visibleEvents.constEnd(); ++i)
|
|
{
|
|
LtsTimelineClassic::Event *e = (*i);
|
|
|
|
if (e->startTime() >= startTime && (e->startTime() + e->duration()) <= endTime)
|
|
newEventList += e;
|
|
}
|
|
|
|
if (newEventList.isEmpty())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This filter has no results"), tr("No Events found"));
|
|
return;
|
|
}
|
|
|
|
if (newEventList.isEmpty())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No Events to show"));
|
|
return;
|
|
}
|
|
|
|
if (m_allEventsListDialog == nullptr)
|
|
{
|
|
m_allEventsListDialog = new EventListDialog(m_menuGroup, m_session, m_ppmDtc, m_pdmDtc, m_ismDtc, m_flmIfc, false );
|
|
connect(m_allEventsListDialog.data(), &EventListDialog::signalShowEventDetails,
|
|
this, &TimelineViewDialog::slotShowEventDetails);
|
|
|
|
if (!m_allEventsListDialog->init(m_detailData, newEventList, true))
|
|
{
|
|
m_allEventsListDialog->deleteLater();
|
|
m_allEventsListDialog = nullptr;
|
|
return;
|
|
}
|
|
addDialog(m_allEventsListDialog, m_menuGroup, QStringLiteral("allEventsListDialog"), LtsWidgets::LayoutArea::eDialogTab);
|
|
}
|
|
else
|
|
{
|
|
m_allEventsListDialog->clearModel();
|
|
m_allEventsListDialog->appendEventList(newEventList);
|
|
focusDialog(m_menuGroup, QStringLiteral("allEventsListDialog"), LtsWidgets::LayoutArea::eDialogTab);
|
|
}
|
|
|
|
}
|
|
|
|
void TimelineViewDialog::setTimelineUsable(bool usable)
|
|
{
|
|
m_ui->widget->setEnabled(usable);
|
|
m_ui->sbSpan->setEnabled(usable);
|
|
m_ui->pbLive->setEnabled(usable);
|
|
|
|
m_ui->lblNoEventsSelected->setVisible(!usable);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::updateActiveEventTypesByFilters()
|
|
{
|
|
QSet<int> activeEventTypes;
|
|
|
|
for (auto i1 = m_filter.constBegin(); i1 != m_filter.constEnd(); ++i1)
|
|
{
|
|
const QJsonObject &filter = (*i1).toObject();
|
|
|
|
QString eventTypeString = filter[QStringLiteral("EventType")].toString();
|
|
bool k = false;
|
|
int eventType = eventTypeString.toInt(&k);
|
|
|
|
if (!k || eventType < 0 || !filter[QStringLiteral("Active")].toBool(false))
|
|
continue;
|
|
|
|
activeEventTypes.insert(eventType);
|
|
}
|
|
|
|
m_model->setActiveEventTypeIds(activeEventTypes);
|
|
|
|
setTimelineUsable(!activeEventTypes.isEmpty());
|
|
|
|
if (m_legendDialog != nullptr)
|
|
m_legendDialog->setActiveEventTypeIds(activeEventTypes);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::updateFiltersByActiveEventTypes()
|
|
{
|
|
const QSet<int> &activeEventTypes = m_model->activeEventTypeIds();
|
|
QVector<int> filterEventTypes;
|
|
|
|
|
|
for (QJsonValueRef filter : m_filter)
|
|
{
|
|
QJsonObject filterObj = filter.toObject();
|
|
|
|
QString eventTypeString = filterObj[QStringLiteral("EventType")].toString();
|
|
bool k = false;
|
|
int eventType = eventTypeString.toInt(&k);
|
|
|
|
if (!k || eventType < 0)
|
|
continue;
|
|
|
|
if (!filterEventTypes.contains(eventType))
|
|
filterEventTypes.append(eventType);
|
|
|
|
bool active = filterObj[QStringLiteral("Active")].toBool(false);
|
|
|
|
if (active && !activeEventTypes.contains(eventType))
|
|
active = false;
|
|
else if (!active && activeEventTypes.contains(eventType))
|
|
active = true;
|
|
|
|
filterObj[QStringLiteral("Active")] = active;
|
|
filter = filterObj;
|
|
}
|
|
|
|
|
|
|
|
for (int eventType : activeEventTypes)
|
|
{
|
|
if (!filterEventTypes.contains(eventType))
|
|
{
|
|
QJsonObject filter;
|
|
|
|
filter[QStringLiteral("EventType")] = QString::number(eventType);
|
|
filter[QStringLiteral("Active")] = true;
|
|
|
|
m_filter.append(filter);
|
|
}
|
|
}
|
|
|
|
applyFilter(m_filter, false , true);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::applyFilter(const QJsonArray &filter, bool doUpdateActiveEventTypes, bool reloadFilterWindow)
|
|
{
|
|
m_filter = filter;
|
|
setFilter(m_detailData, m_model->getRootItem()->getFullEventList(true, true), filter, this);
|
|
m_model->applyFilter(filter);
|
|
|
|
if (doUpdateActiveEventTypes)
|
|
updateActiveEventTypesByFilters();
|
|
|
|
if (reloadFilterWindow && m_filterWindow != nullptr)
|
|
m_filterWindow->loadFilters(filter);
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotApplyFilter(const QJsonArray &filter)
|
|
{
|
|
applyFilter(filter, true , false );
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotWaitForReady()
|
|
{
|
|
|
|
ExerciseManagement::Exercise ex = m_exmDtc->exercise(m_session->partitionId());
|
|
if (ex.id() > 0)
|
|
{
|
|
qint64 partitionTime = 0;
|
|
|
|
partitionTime = m_session->partitionTime();
|
|
|
|
if (partitionTime < 1)
|
|
{
|
|
emit signalWaitForReady();
|
|
return;
|
|
}
|
|
|
|
if (partitionTime < ex.beginTime())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("The current time is outside of the Exercise's period.<br>Events are only recorded in Exercise period boundaries."), tr("No Events available"));
|
|
WARNING_LOG(m_logger) << "Partition time was " << partitionTime << ", exercise begin time: " << ex.beginTime();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING_LOG(m_logger) << "TimelineViewDialog::init: could not check exercise's boundaries!";
|
|
}
|
|
|
|
LtsWidgets::LtsGlobalWaitDialog::getInstance()->done();
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::slotShowEventDetails(const Event *event)
|
|
{
|
|
switch (event->typeId())
|
|
{
|
|
case ProjectDataManagement::EventType::BiteMessage:
|
|
{
|
|
m_ppmInfoIfc->showBiteWindow(event->detailData());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
addDialog(LtsWidgets::initDialog(new ShowDetailsDialog(),
|
|
m_detailData, event,
|
|
m_session,
|
|
m_replayAppSession, m_avmIfc, m_mrkIfc, m_fltParticipantIfc, m_fltAesIfc, m_fltBuildingComponentIfc,
|
|
m_session->app() == LtsAppDescriptor::App::Timeline,
|
|
this, m_streamNameMapping),
|
|
m_menuGroup, QStringLiteral("ShowEventDetails%1").arg(event->uniqueId()), LtsWidgets::LayoutArea::eInfoTab);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::showDetails(const EventList &eventList)
|
|
{
|
|
if (eventList.isEmpty())
|
|
{
|
|
LtsWidgets::LtsMessageDialog::showMessage(this, tr("No Events to show"));
|
|
return;
|
|
}
|
|
|
|
if (eventList.count() > 1)
|
|
{
|
|
if (m_eventListDialog == nullptr)
|
|
{
|
|
m_eventListDialog = new EventListDialog(m_menuGroup, m_session, m_ppmDtc, m_pdmDtc, m_ismDtc, m_flmIfc, true );
|
|
connect(m_eventListDialog.data(), &EventListDialog::signalShowEventDetails,
|
|
this, &TimelineViewDialog::slotShowEventDetails);
|
|
|
|
if (!m_eventListDialog->init(m_detailData, eventList, false))
|
|
{
|
|
m_eventListDialog->deleteLater();
|
|
m_eventListDialog = nullptr;
|
|
return;
|
|
}
|
|
|
|
addDialog(m_eventListDialog, m_menuGroup, QStringLiteral("eventListDialog"), LtsWidgets::LayoutArea::eDialogTab);
|
|
}
|
|
else
|
|
{
|
|
m_eventListDialog->appendEventList(eventList);
|
|
focusDialog(m_menuGroup, QStringLiteral("eventListDialog"), LtsWidgets::LayoutArea::eDialogTab);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
slotShowEventDetails(eventList.at(0));
|
|
}
|
|
}
|
|
|
|
|
|
void TimelineViewDialog::showDetailsAction(EventGraphic *eg, int action)
|
|
{
|
|
if (action != EventGraphic::ACTION_LEFT_CLICKED)
|
|
return;
|
|
|
|
showDetails(eg->eventList());
|
|
}
|
|
|
|
}
|