Adds initial intermediate qt6 porting state

This commit is contained in:
torsten committed 2026-08-17 17:54:56 +02:00
1 parent 99136e9460
commit d176b5e0d7
11247 files changed
+1891537

No files matched your search

@@ -0,0 +1,135 @@
#
# $Id$
# $HeadURL$
# $Author$
#
# Created by Mike Wille, SLSE, 2017-02-10
#
# EventFilter
SET(EventFilter_SRCS
EventFilter/AttributeEditingModeUI.h
EventFilter/AttributeEditingModeUI.cpp
EventFilter/AttributeSelectionModeUI.h
EventFilter/AttributeSelectionModeUI.cpp
EventFilter/FilterWindow.h
EventFilter/FilterWindow.cpp
EventFilter/FilterTableEntry.h
EventFilter/FilterTableEntry.cpp
EventFilter/FilterTableEntryAttribute.h
EventFilter/FilterTableEntryAttribute.cpp
EventFilter/interpreter/FilterWorker.h
EventFilter/interpreter/FilterWorker.cpp
EventFilter/widgets/AbstractAttributeWidget.cpp
EventFilter/widgets/ComboBox.cpp
EventFilter/widgets/TimeRangeWidget.cpp
EventFilter/widgets/AreaWidget.cpp
EventFilter/widgets/DefaultRangeWidget.cpp
EventFilter/widgets/CheckBoxWidget.cpp
EventFilter/widgets/RadiusWidget.cpp
EventFilter/interpreter/InfoWindow.h
EventFilter/interpreter/InfoWindow.cpp
EventFilter/interpreter/FilterEquationFunctions.cpp
EventFilter/interpreter/FilterValueInterpreter.cpp
EventFilter/widgets/AbstractAttributeWidget.h
EventFilter/widgets/ComboBox.h
EventFilter/widgets/TimeRangeWidget.h
EventFilter/widgets/AreaWidget.h
EventFilter/widgets/DefaultRangeWidget.h
EventFilter/widgets/CheckBoxWidget.h
EventFilter/widgets/RadiusWidget.h
EventFilter/interpreter/FilterEquationFunctions.h
EventFilter/interpreter/FilterValueInterpreter.h
detail_data.h
detail_data.cpp
excon_filter.h
excon_filter.cpp
logger.h
logger.cpp
)
SET(EventFilter_UICS
EventFilter/ui/FilterWindowUi.ui
)
# Timeline
SET(tln_view_gui_SRCS
attribute_value_lookup.cpp
attribute_value_lookup.h
tln_view_gui_plugin.cpp
tln_view_gui_plugin.h
tln_dialog.cpp
tln_dialog.h
tln_dialog_model.cpp
tln_dialog_model.h
tln_cache_dialog.cpp
tln_cache_dialog.h
tln_show_details.cpp
tln_show_details.h
tln_event_list.h
tln_event_list.cpp
tln_event_list_model.h
tln_event_list_model.cpp
tln_event_list_columns.h
tln_event_list_columns.cpp
tln_legend.h
tln_legend.cpp
${EventFilter_SRCS}
)
NGL_WRAP_UI(tln_view_gui_SRCS
tln_dialog.ui
tln_cache_dialog.ui
tln_show_details.ui
tln_event_list.ui
tln_event_list_columns.ui
tln_legend.ui
${EventFilter_UICS}
)
NGL_ADD_LIBRARY(WS TlnViewGuiPlugin MODULE ${tln_view_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(TlnViewGuiPlugin
Qt5::Widgets
Qt5::WebSockets
LtsAppManager
LtsDataView
LtsTimelineClassic
LtsPrinting
LtsSession
LtsSessionData
LtsUtilsCore # data mod
LtsUtilsGuiDds
LtsUtilsSettings
LtsWidgets
NGLLogger
ngltools # dtg
AvmDataPluginInterface
ExmDataPluginInterface
IsmDataPluginInterface
MrkDataPluginInterface
OpmDataPluginInterface
PdmDataPluginInterface
PpmDataPluginInterface
FlmExplorerGuiPluginInterface
FltAesGuiPluginInterface # SitMap Filter
TlnDataPluginInterface
TlnViewGuiPluginInterface
MrkCommon # SitMap Filter Helper
)
NGL_INSTALL_TARGET(TlnViewGuiPlugin)
@@ -0,0 +1,220 @@
#include "AttributeEditingModeUI.h"
#include "../detail_data.h"
#include "widgets/TimeRangeWidget.h"
#include "widgets/DefaultRangeWidget.h"
#include "widgets/ComboBox.h"
#include "widgets/CheckBoxWidget.h"
#include "widgets/AreaWidget.h"
#include "widgets/RadiusWidget.h"
#include "logger.h"
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
namespace Timeline
{
AbstractAttributeWidget *EditingModeUI::createAttributeUIWidget(DetailData *detailData, const QString &attributeType,
int eventType, const QString &initialValue)
{
AbstractAttributeWidget *resultWidget = nullptr;
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
int attributeUIType = detailData->attributeUITypeLookup.getUIType(concreteAttributeType);
if (attributeUIType == -1)
return nullptr;
const DetailData::AttributeParameterLookup::ParameterMap &pm = detailData->attributeParameterLookup.getParameterMap(concreteAttributeType);
switch (attributeUIType)
{
case DetailData::ATTRIBUTE_UI_TYPE_COMBO_BOX:
{
resultWidget = new ComboBox(detailData, concreteAttributeType, eventType, initialValue);
break;
}
case DetailData::ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET:
{
bool minb = false;
unsigned int min = pm.value(DetailData::UI_PARAM_TYPE_MIN).toUInt(&minb);
bool maxb = false;
unsigned int max = pm.value(DetailData::UI_PARAM_TYPE_MAX).toUInt(&maxb);
QString prefix = pm.value(DetailData::UI_PARAM_TYPE_PREFIX).toString();
QString suffix = pm.value(DetailData::UI_PARAM_TYPE_SUFFIX).toString();
if (!minb || !maxb)
{
WARNING_LOG(m_logger) << "createAttributeUIWidget: !minb (" << minb << ") || !maxb (" << maxb << ")";
break;
}
resultWidget = new DefaultRangeWidget(min, max, prefix, suffix, initialValue);
break;
}
case DetailData::ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET:
{
bool n1k = false;
int n1 = pm.value(DetailData::UI_PARAM_TYPE_N1).toUInt(&n1k);
bool n2k = false;
int n2 = pm.value(DetailData::UI_PARAM_TYPE_N2).toUInt(&n2k);
bool o1k = false;
int o1 = pm.value(DetailData::UI_PARAM_TYPE_O1).toUInt(&o1k);
bool o2k = false;
int o2 = pm.value(DetailData::UI_PARAM_TYPE_O2).toUInt(&o2k);
bool rk = false;
int r = pm.value(DetailData::UI_PARAM_TYPE_RAD).toUInt(&rk);
if (n1k && n2k && o1k && o2k && rk)
{
resultWidget = new RadiusWidget(n1, n2, o1, o2, r);
break;
}
WARNING_LOG(m_logger) << "DetailData::ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET: errorious values!";
break;
}
case DetailData::ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET:
{
bool n1k = false;
int n1 = pm.value(DetailData::UI_PARAM_TYPE_N1).toUInt(&n1k);
bool n2k = false;
int n2 = pm.value(DetailData::UI_PARAM_TYPE_N2).toUInt(&n2k);
bool o1k = false;
int o1 = pm.value(DetailData::UI_PARAM_TYPE_O1).toUInt(&o1k);
bool o2k = false;
int o2 = pm.value(DetailData::UI_PARAM_TYPE_O2).toUInt(&o2k);
if (n1k && n2k && o1k && o2k)
{
resultWidget = new AreaWidget(n1, n2, o1, o2);
break;
}
WARNING_LOG(m_logger) << "DetailData::ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET: errorious values!";
break;
}
case DetailData::ATTRIBUTE_UI_TYPE_CHECKBOX:
{
resultWidget = new CheckBoxWidget(detailData, concreteAttributeType, initialValue);
break;
}
case DetailData::ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET:
{
TimeRangeWidget *trw = new TimeRangeWidget(detailData, initialValue);
detailData->createRetrieveCurrentTimeCallback(trw->m_edit1);
detailData->createRetrieveCurrentTimeCallback(trw->m_edit2);
resultWidget = trw;
break;
}
default:
{
WARNING_LOG(m_logger) << "createAttributeUIWidget: invalid attribute type #" << attributeUIType << "!";
break;
}
}
return resultWidget;
}
void EditingModeUI::addAttributeContainer(int eventType, const QString &initialValue)
{
AbstractAttributeWidget *attributeUIWidget = createAttributeUIWidget(m_detailData, attributeType, eventType, initialValue);
if (attributeUIWidget == nullptr)
{
DEBUG_LOG(m_logger) << "addAttributeContainer: !attributeUIWidget";
return;
}
connect(attributeUIWidget, &AbstractAttributeWidget::destroyed, this, &EditingModeUI::signalChanges);
connect(attributeUIWidget, &AbstractAttributeWidget::signalChanges, this, &EditingModeUI::signalChanges);
attributeValuesLayout->insertWidget(0, attributeUIWidget, 0, Qt::AlignTop);
attributeUIWidget->setFocus();
}
EditingModeUI::EditingModeUI(DetailData *detailData, const QString &attributeType, QWidget *parent)
: QWidget(parent)
, attributeType(attributeType)
, m_detailData(detailData)
, m_logger(getLogger("EventFilter.EditingModeUI"))
{
QVBoxLayout *editingModeLayout = new QVBoxLayout;
QWidget *filterTextWidget = new QWidget;
QHBoxLayout *filterTextLayout = new QHBoxLayout;
filterTextWidget->setLayout(filterTextLayout);
pbDelete = new QPushButton(QStringLiteral("-"));
pbDelete->setToolTip(tr("Delete this attribute and all its values"));
pbDelete->setPalette(QPalette(QColor("red")));
pbDelete->setMaximumWidth(30);
lbFilterText = new QLabel;
filterTextLayout->addWidget(lbFilterText, 0, Qt::AlignLeft);
filterTextLayout->addWidget(pbDelete, 1, Qt::AlignLeft);
QWidget *attributeValuesWidget = new QWidget;
attributeValuesLayout = new QVBoxLayout();
attributeValuesWidget->setLayout(attributeValuesLayout);
pbAddAttributeContainer = new QPushButton(tr("Add Value"));
pbAddAttributeContainer->setPalette(QPalette(QColor("green")));
setLayout(editingModeLayout);
editingModeLayout->addWidget(filterTextWidget, 0, Qt::AlignTop);
QWidget *horizontalLineWidget = new QWidget;
horizontalLineWidget->setFixedHeight(2);
horizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
horizontalLineWidget->setStyleSheet(QStringLiteral("background-color: #c0c0c0;"));
editingModeLayout->addWidget(horizontalLineWidget, 0, Qt::AlignTop);
editingModeLayout->addWidget(pbAddAttributeContainer, 0, Qt::AlignTop | Qt::AlignLeft);
editingModeLayout->addWidget(attributeValuesWidget, 0, Qt::AlignTop);
}
EditingModeUI::~EditingModeUI()
{
const auto children = findChildren<AbstractAttributeWidget*>();
for (auto child : children)
child->disconnect(this);
}
}
@@ -0,0 +1,44 @@
#pragma once
#include <NGLLogger/INGLLogger.h>
#include <QWidget>
class QLabel;
class QPushButton;
class QVBoxLayout;
namespace Timeline
{
class DetailData;
class AbstractAttributeWidget;
class EditingModeUI : public QWidget
{
Q_OBJECT
public:
explicit EditingModeUI(DetailData *detailData, const QString &attributeType, QWidget *parent);
~EditingModeUI();
void addAttributeContainer(int eventType, const QString &initialValue = QString());
QLabel *lbFilterText;
QPushButton *pbDelete;
QVBoxLayout *attributeValuesLayout;
QPushButton *pbAddAttributeContainer;
private:
Timeline::AbstractAttributeWidget *createAttributeUIWidget(DetailData *detailData, const QString &attributeType,
int eventType, const QString &initialValue);
signals:
void signalChanges();
private:
QString attributeType;
DetailData *m_detailData;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,74 @@
#include "../detail_data.h"
#include "AttributeSelectionModeUI.h"
#include "logger.h"
namespace Timeline
{
QComboBox *SelectionModeUI::createAttributesComboBox(int eventType)
{
QComboBox *cbAttributes = new QComboBox();
DetailData::AttributeEventLookup::AttributeList attributeList = m_detailData->attributeEventLookup.getEventsAttributeList(eventType);
for (auto i = attributeList.constBegin(); i != attributeList.constEnd(); ++i)
{
const QString &attributeKey = m_detailData->attributeRedirectionLookup.getRedirection(*i);
if (m_detailData->attributeInterpreterLookup.getInterpreterType(attributeKey) == DetailData::INTERPRETER_TYPE_NONE)
continue;
QString cbAttribute = m_detailData->attributeTypeLookup.getAttributeText(attributeKey);
if (cbAttribute.isEmpty())
{
WARNING_LOG(m_logger) << "SelectionModeUI::createAttributesComboBox: event type " << eventType << " has no attribute text for attribute " << attributeKey << " for attribute event lookup - not added";
}
else
{
cbAttributes->addItem(cbAttribute);
}
}
return cbAttributes;
}
SelectionModeUI::SelectionModeUI(DetailData *detailData, const int eventType)
: eventType(eventType)
, m_detailData(detailData)
, m_logger(getLogger("EventFilter.AttributeEditingModeUI"))
{
selectionModeWidget = new QWidget();
selectionModeLayout = new QHBoxLayout();
lbFilterText = new QLabel(tr("Select attribute type to filter:"));
cbAttributeType = createAttributesComboBox(eventType);
pbAddEditingMode = new QPushButton(tr("OK"));
pbAddEditingMode->setToolTip(tr("Add this attribute and start adding values"));
pbAddEditingMode->setPalette(QPalette(QColor("green")));
pbAddEditingMode->setMaximumWidth(30);
pbDeleteFilter = new QPushButton(QStringLiteral("-"));
pbDeleteFilter->setPalette(QPalette(QColor("red")));
pbDeleteFilter->setToolTip(tr("Delete this attribute and all its values"));
pbDeleteFilter->setMaximumWidth(30);
selectionModeLayout->addWidget(lbFilterText, 0, Qt::AlignCenter);
selectionModeLayout->addWidget(cbAttributeType, 0, Qt::AlignTop);
selectionModeLayout->addWidget(pbAddEditingMode, 0, Qt::AlignTop);
selectionModeLayout->addWidget(pbDeleteFilter, 1, Qt::AlignTop);
selectionModeWidget->setLayout(selectionModeLayout);
}
}
@@ -0,0 +1,53 @@
#pragma once
#include <NGLLogger/INGLLogger.h>
#include <QComboBox>
#include <QWidget>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
namespace Timeline
{
class DetailData;
class SelectionModeUI : public QObject
{
Q_OBJECT
private:
SelectionModeUI &operator=(const SelectionModeUI &);
public:
QComboBox *createAttributesComboBox(int eventType);
explicit SelectionModeUI(DetailData *detailData, const int eventType);
~SelectionModeUI()
{
delete lbFilterText;
delete cbAttributeType;
delete pbAddEditingMode;
delete selectionModeLayout;
delete selectionModeWidget;
}
int eventType;
QWidget *selectionModeWidget;
QHBoxLayout *selectionModeLayout;
QLabel *lbFilterText;
QComboBox *cbAttributeType;
QPushButton *pbAddEditingMode;
QPushButton *pbDeleteFilter;
DetailData *m_detailData;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,328 @@
#include "FilterTableEntry.h"
#include "FilterTableEntryAttribute.h"
#include "interpreter/FilterWorker.h"
#include "../detail_data.h"
#include "logger.h"
#include <QColor>
#include <QSizePolicy>
#include <QJsonArray>
#include <QDebug>
namespace Timeline
{
FilterTableEntry::FilterTableEntry(DetailData *detailData, const int &eventType, const bool &active, QWidget *parent)
: QGroupBox(parent)
, m_logger(getLogger("EventFilter.FilterTableEntry"))
, m_eventType(eventType)
, m_mainLayout(new QVBoxLayout())
, m_topLayout(new QHBoxLayout())
, m_centerLayout(new QHBoxLayout())
, m_cbEventSelector(nullptr)
, m_pbDelete(new QPushButton(QStringLiteral("-")))
, m_pbFoundEvents(new QPushButton(tr("Show Events")))
, m_pbFilterActive(new QPushButton(tr("Active")))
, m_pbOK(new QPushButton(tr("OK")))
, m_lbSelectText(new QLabel(tr("Select event type to filter:")))
, m_detailData(detailData)
{
m_cbEventSelector = getEventTypesComboBox();
m_pbDelete->setPalette(QPalette(QColor("red")));
m_pbDelete->setToolTip(tr("Delete this filter and all its attributes"));
m_pbFilterActive->setPalette(QPalette(QColor("orange")));
m_pbFoundEvents->setPalette(QPalette(QColor("orange")));
m_pbOK->setPalette(QPalette(QColor("green")));
m_pbOK->setToolTip(tr("Add this filter and start adding attributes (when needed)"));
connect(m_pbFilterActive, &QPushButton::clicked, this, &FilterTableEntry::signalChanges);
setLayout(m_mainLayout);
QWidget *topLayoutWidget = new QWidget(this);
topLayoutWidget->setLayout(m_topLayout);
m_mainLayout->addWidget(topLayoutWidget, 0, Qt::AlignTop);
m_topLayout->addWidget(m_lbSelectText, 0, Qt::AlignLeft);
m_topLayout->addWidget(m_cbEventSelector, 0, Qt::AlignLeft);
m_pbOK->setMinimumWidth(30);
m_pbOK->setMaximumWidth(30);
m_topLayout->addWidget(m_pbOK, 0, Qt::AlignLeft);
connect(m_pbOK, &QPushButton::clicked, this, &FilterTableEntry::slotSelectEventType);
connect(m_pbDelete, &QPushButton::clicked, this, &FilterTableEntry::deleteLater);
m_pbDelete->setMinimumWidth(30);
m_pbDelete->setMaximumWidth(30);
m_topLayout->addWidget(m_pbDelete, 1, Qt::AlignLeft);
QWidget *centerLayoutWidget = new QWidget(this);
centerLayoutWidget->setStyleSheet(topLayoutWidget->styleSheet());
centerLayoutWidget->setLayout(m_centerLayout);
m_mainLayout->addWidget(centerLayoutWidget, 0);
if (m_eventType > -1)
slotSelectEventType();
m_pbFoundEvents->setEnabled(active);
m_pbFilterActive->setCheckable(true);
m_pbFilterActive->setChecked(active);
m_pbFilterActive->setToolTip(m_pbFilterActive->isChecked() ? tr("Filter is active") : tr("Filter is inactive"));
}
FilterTableEntry::~FilterTableEntry()
{
const auto children = findChildren<FilterTableEntryAttribute *>();
for (auto child : children)
child->disconnect(this);
}
void FilterTableEntry::updateData()
{
for (int i = 0; i < m_centerLayout->count(); i++)
{
FilterTableEntryAttribute *ftec = dynamic_cast<FilterTableEntryAttribute *>(m_centerLayout->itemAt(i)->widget());
if (!ftec)
{
WARNING_LOG(m_logger) << "FilterTableEntry::filterText(): !ftec";
continue;
}
ftec->updateData(m_detailData);
}
}
QComboBox *FilterTableEntry::getEventTypesComboBox()
{
QComboBox *cbEventTypes = new QComboBox();
cbEventTypes->addItems(m_detailData->eventTypeLookup.getEventTexts());
cbEventTypes->model()->sort(0);
connect(cbEventTypes, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &FilterTableEntry::signalChanges);
return cbEventTypes;
}
const QJsonObject FilterTableEntry::filter(bool typeSafe) const
{
if (m_eventType == -1)
{
WARNING_LOG(m_logger) << "FilterTableEntry has no event type.";
return {};
}
if (!m_centerLayout->count())
{
}
QJsonObject result;
QString eventTypeString;
if (typeSafe)
eventTypeString = QString::number(m_eventType);
else
eventTypeString = m_detailData->eventTypeLookup.getEventText(m_eventType);
if (!eventTypeString.length())
return QJsonObject();
result[QStringLiteral("EventType")] = eventTypeString;
QJsonArray attributes;
for (int i = 0; i < m_centerLayout->count(); i++)
{
FilterTableEntryAttribute *ftec = dynamic_cast<FilterTableEntryAttribute *>(m_centerLayout->itemAt(i)->widget());
if (!ftec)
{
WARNING_LOG(m_logger) << "FilterTableEntry::filterText(): !ftec";
continue;
}
QJsonObject filterTile = ftec->filter(typeSafe);
if (filterTile.isEmpty())
continue;
attributes.append(filterTile);
}
result[QStringLiteral("Attributes")] = attributes;
result[QStringLiteral("Active")] = m_pbFilterActive->isChecked();
return result;
}
void FilterTableEntry::slotSelectEventType()
{
delete m_lbSelectText;
if (m_cbEventSelector)
{
if (m_eventType == -1)
{
m_eventType = m_detailData->eventTypeLookup.getEventType(m_cbEventSelector->currentText());
}
m_lbEventName = new QLabel(QString(tr("Filter by event type: <b>%1</b>")).arg(m_detailData->eventTypeLookup.getEventText(m_eventType)));
m_lbEventName->setMinimumWidth(m_cbEventSelector->width());
delete m_cbEventSelector;
m_cbEventSelector = nullptr;
m_topLayout->insertWidget(0, m_lbEventName);
}
if (m_eventType == -1)
{
WARNING_LOG(m_logger) << "slotSelectEventType: m_eventType == -1";
return;
}
delete m_pbOK;
QWidget *horizontalLineWidget = new QWidget();
horizontalLineWidget->setFixedHeight(2);
horizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
horizontalLineWidget->setStyleSheet(QStringLiteral("background-color: #c0c0c0;"));
m_mainLayout->insertWidget(1, horizontalLineWidget, 0, Qt::AlignTop);
delete m_pbDelete;
m_pbDelete = new QPushButton(QStringLiteral("-"));
m_pbDelete->setToolTip(tr("Delete this filter and all its attributes"));
m_pbDelete->setPalette(QPalette(QColor("red")));
connect(m_pbDelete, &QPushButton::clicked, this, &FilterTableEntry::deleteLater);
m_pbDelete->setMinimumWidth(30);
m_pbDelete->setMaximumWidth(30);
m_topLayout->addWidget(m_pbDelete, 0, Qt::AlignLeft);
m_topLayout->addWidget(m_pbFilterActive, 0, Qt::AlignLeft);
connect(m_pbFilterActive, &QPushButton::clicked, this, &FilterTableEntry::slotFilterActiveClicked);
connect(m_pbFoundEvents, &QPushButton::clicked, this, &FilterTableEntry::slotShowEvents);
m_pbFoundEvents->setToolTip(tr("Show all events that fit to this filter"));
m_topLayout->addWidget(m_pbFoundEvents, 1, Qt::AlignLeft);
DetailData::AttributeEventLookup::AttributeList attributeList = m_detailData->attributeEventLookup.getEventsAttributeList(m_eventType);
QMutableListIterator<QString> it(attributeList);
while (it.hasNext())
{
const QString attributeType = it.next();
if (m_detailData->attributeInterpreterLookup.getInterpreterType(attributeType) == DetailData::INTERPRETER_TYPE_NONE)
it.remove();
}
if (attributeList.isEmpty())
return;
QPushButton *pbAddAttribute = new QPushButton(tr("Add Attribute"));
pbAddAttribute->setPalette(QPalette(QColor("green")));
connect(pbAddAttribute, &QPushButton::clicked, this, &FilterTableEntry::slotAddAttribute);
m_mainLayout->insertWidget(2, pbAddAttribute, 0, Qt::AlignLeft);
}
void FilterTableEntry::slotShowEvents()
{
QJsonArray a;
a.append(filter(true ));
emit signalShowEvents(a);
}
void FilterTableEntry::slotFilterActiveClicked()
{
if (m_pbFilterActive->isChecked())
{
m_pbFilterActive->setPalette(QPalette(QColor("orange")));
m_pbFilterActive->setToolTip(tr("Filter is active"));
m_pbFoundEvents->setPalette(QPalette(QColor("orange")));
m_pbFoundEvents->setEnabled(true);
}
else
{
m_pbFilterActive->setPalette(QPalette(QColor("grey")));
m_pbFilterActive->setToolTip(tr("Filter is inactive"));
m_pbFoundEvents->setPalette(QPalette(QColor("grey")));
m_pbFoundEvents->setEnabled(false);
}
}
void FilterTableEntry::slotAddAttribute()
{
addAttribute();
}
bool FilterTableEntry::hasAttributes() const
{
qWarning() << "hasAttributes? children: " << m_centerLayout->children().count();
return !!m_centerLayout->children().count();
}
FilterTableEntryAttribute *FilterTableEntry::addAttribute(const QString &attributeType)
{
FilterTableEntryAttribute *ftec = new FilterTableEntryAttribute(m_detailData, m_eventType, attributeType, this);
connect(ftec, &FilterTableEntryAttribute::signalChanges, this, &FilterTableEntry::signalChanges);
connect(ftec, &FilterTableEntryAttribute::destroyed, this, &FilterTableEntry::signalChanges);
m_centerLayout->insertWidget(0, ftec, 1, Qt::AlignLeft);
return ftec;
}
}
@@ -0,0 +1,74 @@
#pragma once
#include "FilterTableEntryAttribute.h"
#include <QWidget>
#include <QHBoxLayout>
#include <QPushButton>
#include <QComboBox>
#include <QPaintEvent>
#include <QPainter>
#include <QList>
#include <QGroupBox>
namespace Timeline
{
class DetailData;
class FilterTableEntry : public QGroupBox
{
Q_OBJECT
public:
explicit FilterTableEntry(DetailData *detailData, const int &eventType = -1, const bool &active = true, QWidget *parent = nullptr);
~FilterTableEntry();
const QJsonObject filter(bool typeSafe = false) const;
FilterTableEntryAttribute *addAttribute(const QString &attributeType = QString());
bool hasAttributes() const;
void updateData();
private:
NGL::INGLLogger &m_logger;
QComboBox *getEventTypesComboBox();
int m_eventType;
QVBoxLayout *m_mainLayout{nullptr};
QHBoxLayout *m_topLayout{nullptr};
QHBoxLayout *m_centerLayout{nullptr};
QComboBox *m_cbEventSelector{nullptr};
QLabel *m_lbEventName{nullptr};
QPushButton *m_pbDelete{nullptr};
QPushButton *m_pbFoundEvents{nullptr};
QPushButton *m_pbFilterActive{nullptr};
QPushButton *m_pbOK{nullptr};
QLabel *m_lbSelectText{nullptr};
DetailData *m_detailData{nullptr};
signals:
void signalShowEvents(const QJsonArray &filter);
void signalChanges();
private slots:
void slotAddAttribute();
void slotFilterActiveClicked();
void slotSelectEventType();
void slotShowEvents();
public slots:
};
}
@@ -0,0 +1,212 @@
#include "interpreter/FilterWorker.h"
#include "FilterTableEntryAttribute.h"
#include "widgets/AbstractAttributeWidget.h"
#include "logger.h"
#include "../detail_data.h"
#include <QVBoxLayout>
#include <QJsonObject>
#include <QJsonArray>
namespace Timeline
{
FilterTableEntryAttribute::FilterTableEntryAttribute(DetailData *detailData, int eventType, const QString &attributeType, QWidget *parent)
: QGroupBox(parent)
, m_eventType(eventType)
, m_attributeType(attributeType)
, m_selectionModeUI(nullptr)
, m_editionModeUI(nullptr)
, m_attributesLayout(new QVBoxLayout())
, m_detailData(detailData)
, m_logger(getLogger("EventFilter.FilterTableEntryAttribute"))
{
this->setTitle(QString());
setLayout(m_attributesLayout);
slotAddSelectionMode();
if (!attributeType.isEmpty())
{
m_selectionModeUI->cbAttributeType->setCurrentIndex(m_selectionModeUI->cbAttributeType->findData(QVariant::fromValue<QString>(attributeType)));
slotAddEditingMode(false);
}
}
FilterTableEntryAttribute::~FilterTableEntryAttribute()
{
delete m_editionModeUI;
}
void FilterTableEntryAttribute::updateData(DetailData *detailData)
{
if (!m_editionModeUI)
return;
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++)
{
AbstractAttributeWidget *aaw = dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
if (!aaw)
continue;
aaw->updateData(detailData);
connect(aaw, &AbstractAttributeWidget::deleteClicked, this, [this]()
{
emit attributeChanged(false);
});
}
}
const QJsonObject FilterTableEntryAttribute::filter(bool typeSafe) const
{
if (m_attributeType.isEmpty())
{
WARNING_LOG(m_logger) << "filterText: m_attributeType == -1";
return QJsonObject();
}
QString attributeTypeName;
if (typeSafe)
attributeTypeName = m_attributeType;
else
{
attributeTypeName = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType);
}
if (attributeTypeName.isEmpty())
{
WARNING_LOG(m_logger) << "filterText: !attributeTypeName.length()";
return QJsonObject();
}
QJsonObject result;
result[QStringLiteral("AttributeType")] = attributeTypeName;
QJsonArray values;
if (m_editionModeUI)
{
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++)
{
AbstractAttributeWidget *aaw = dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
if (!aaw)
continue;
QString value = aaw->filterText(typeSafe);
if (value.isEmpty())
continue;
values.append(value);
}
}
result[QStringLiteral("AttributeValues")] = values;
return result;
}
void FilterTableEntryAttribute::slotAddSelectionMode()
{
m_selectionModeUI = new SelectionModeUI(m_detailData, m_eventType);
connect(m_selectionModeUI->pbAddEditingMode, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotAddEditingMode);
connect(m_selectionModeUI->pbDeleteFilter, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotDeleteAttributeContainer);
m_attributesLayout->addWidget(m_selectionModeUI->selectionModeWidget, 0, Qt::AlignTop);
}
void FilterTableEntryAttribute::slotAddEditingMode(bool createBlankContainer)
{
if (!m_selectionModeUI)
return;
QString attributeTypeString;
if (m_attributeType.isEmpty())
{
attributeTypeString = m_selectionModeUI->cbAttributeType->currentText();
m_attributeType = m_detailData->attributeTypeLookup.getAttributeType(attributeTypeString);
}
else
{
attributeTypeString = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType);
}
delete m_selectionModeUI;
m_selectionModeUI = nullptr;
if (m_attributeType.isEmpty())
{
WARNING_LOG(m_logger) << "slotAddEditingMode: invalid attribute type string!";
return;
}
m_editionModeUI = new EditingModeUI(m_detailData, m_attributeType, nullptr);
connect(m_editionModeUI, &EditingModeUI::signalChanges, this, &FilterTableEntryAttribute::signalChanges);
connect(m_editionModeUI, &EditingModeUI::destroyed, this, &FilterTableEntryAttribute::signalChanges);
connect(m_editionModeUI->pbAddAttributeContainer, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotAddAttributeContainer);
connect(m_editionModeUI->pbDelete, &QPushButton::clicked, this, &FilterTableEntryAttribute::slotDeleteAttributeContainer);
m_editionModeUI->lbFilterText->setText(tr("Filter by attribute type: <b>%1</b>").arg(attributeTypeString));
m_attributesLayout->addWidget(m_editionModeUI, 0, Qt::AlignTop);
if (createBlankContainer)
slotAddAttributeContainer();
}
void FilterTableEntryAttribute::slotDeleteAttributeContainer()
{
emit attributeChanged(false);
deleteLater();
}
void FilterTableEntryAttribute::slotAddAttributeContainer()
{
emit signalChanges();
emit attributeChanged(true);
if (m_editionModeUI != nullptr)
m_editionModeUI->addAttributeContainer(m_eventType);
}
}
@@ -0,0 +1,53 @@
#pragma once
#include "AttributeEditingModeUI.h"
#include "AttributeSelectionModeUI.h"
#include <QGroupBox>
class QLabel;
class QVBoxLayout;
namespace Timeline
{
class DetailData;
class FilterTableEntryAttribute : public QGroupBox
{
Q_OBJECT
public:
explicit FilterTableEntryAttribute(DetailData *detailData, int eventType, const QString &attributeType, QWidget *parent = nullptr);
~FilterTableEntryAttribute();
const QJsonObject filter(bool typeSafe = false) const;
void updateData(DetailData *detailData);
int m_eventType;
QString m_attributeType;
SelectionModeUI *m_selectionModeUI;
EditingModeUI *m_editionModeUI;
QVBoxLayout *m_attributesLayout;
QLabel *m_lbSelectText;
DetailData *m_detailData;
signals:
void signalChanges();
void attributeChanged(const bool &hasAttribute);
private:
NGL::INGLLogger &m_logger;
private slots:
void slotAddAttributeContainer();
void slotDeleteAttributeContainer();
void slotAddSelectionMode();
void slotAddEditingMode(bool createBlankContainer = true);
};
}
@@ -0,0 +1,320 @@
#include "FilterWindow.h"
#include "ui_FilterWindowUi.h"
#include "FilterTableEntry.h"
#include "interpreter/FilterWorker.h"
#include "../detail_data.h"
#include "logger.h"
#include <FileManagement/flm_translation.h>
#include <QMessageBox>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
#include <QScopeGuard>
#endif
#include <QDebug>
namespace Timeline
{
FilterWindow::FilterWindow(DetailData *detailData,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
LtsSession::LtsSession *session,
QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_flmIfc(flmIfc)
, m_ui(new Ui::FilterWindow)
, updateTimer(new QTimer(this))
, m_detailData(detailData)
, m_logger(getLogger("EventFilter.FilterWindow"))
, m_session(session)
{
m_ui->setupUi(this);
setMinimumSize(1500, 800);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add,
this, &FilterWindow::slotAddNewFilter);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Show,
this, &FilterWindow::slotShowEvents);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save,
this, &FilterWindow::slotSave);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load,
this, &FilterWindow::slotLoad);
connect(updateTimer, &QTimer::timeout, this, &FilterWindow::slotUpdate);
updateTimer->setInterval(5000);
updateTimer->start();
setOnlineHelpFilename(QStringLiteral("Timeline-Filter_Functions"));
}
FilterWindow::~FilterWindow()
{
const QList<FilterTableEntry*> lst = findChildren<FilterTableEntry*>();
for (FilterTableEntry *fte : lst)
fte->disconnect(this);
updateTimer->stop();
delete m_ui;
}
void FilterWindow::retranslate()
{
translate(m_ui, tr("Filters"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setText(tr("Add Filter"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Show)->setText(tr("Show Events"));
}
void FilterWindow::slotSave()
{
int fileId = m_flmIfc->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(),
filterToDoc(exportFilter()));
if (fileId > 0)
{
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
__unchange__();
}
else
ERROR_LOG(m_logger) << "Could not save file in library ";
}
void FilterWindow::slotUpdate()
{
for (int i = 0; i < m_ui->filterContainer->count(); i++)
{
FilterTableEntry *fte = qobject_cast<FilterTableEntry *>(m_ui->filterContainer->itemAt(i)->widget());
if (!fte)
continue;
fte->updateData();
}
}
FilterTableEntry *FilterWindow::addNewFilter(const int eventType, bool active)
{
FilterTableEntry *fte = new FilterTableEntry(m_detailData, eventType, active, this);
connect(fte, &FilterTableEntry::signalChanges, this, &FilterWindow::slotChangesMade);
connect(fte, &FilterTableEntry::destroyed, this, &FilterWindow::slotChangesMade);
connect(fte, &FilterTableEntry::signalShowEvents, this, &FilterWindow::signalShowEvents);
m_ui->filterContainer->addWidget(fte);
slotChangesMade();
return fte;
}
void FilterWindow::slotAddNewFilter()
{
addNewFilter();
}
const QJsonArray FilterWindow::exportFilter() const
{
if (!m_ui->filterContainer->count())
return QJsonArray();
QJsonArray result;
for (int i = 0; i < m_ui->filterContainer->count(); i++)
{
FilterTableEntry *fte = qobject_cast<FilterTableEntry *>(m_ui->filterContainer->itemAt(i)->widget());
if (!fte)
continue;
const QJsonObject filterTile = fte->filter(true );
if (filterTile.isEmpty())
continue;
result.append(filterTile);
}
qWarning() << "filter text:" << result;
return result;
}
const QByteArray FilterWindow::filterToDoc(const QJsonArray &flt)
{
QJsonObject obj;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter);
obj[QStringLiteral("Filter")] = flt;
QJsonDocument doc(obj);
return doc.toJson(QJsonDocument::Compact);
}
bool FilterWindow::apply()
{
slotApplyFilter();
return true;
}
void FilterWindow::aboutToClose()
{
}
void FilterWindow::slotApplyFilter()
{
emit signalApplyFilter(exportFilter());
}
void FilterWindow::slotShowEvents()
{
emit signalShowEvents(exportFilter());
}
void FilterWindow::slotLoad()
{
QByteArray content;
int fileId = m_flmIfc->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter));
if (fileId > 0)
{
int msgResult = QMessageBox::question(this,
tr("Load filter set"),
tr("Do you really want to discard current filter set to load the requested filter set?\n"
"\n"
"Yes, discard current filter set and load a filter set.\n"
"No, do not make any changes."),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (msgResult != QMessageBox::Yes)
return;
if (!m_flmIfc->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TLNTimelineFilter)))
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Invalid xml file content"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes,
texts);
}
else
{
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
const QJsonArray tlnFilter(obj.value(QStringLiteral("Filter")).toArray());
loadFilters(tlnFilter);
slotChangesMade();
}
}
}
bool FilterWindow::loadFilters(const QJsonArray &filter)
{
setUnchangeable();
#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)
auto unchangableReset = qScopeGuard([this] { setUnchangeable(false); });
#else
std::shared_ptr<int> unchangeableReset(nullptr, [this](int *) { setUnchangeable(false); });
#endif
FilterWorker::GetModelFilterListResult result = FilterWorker::getModelFilterList(m_detailData, filter, true);
if (!FilterWorker::getInstance()->handleResultValues(result.resultValueList, this, true))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("The selected filter set is invalid and cannot be loaded."), tr("Cannot load filter"));
return false;
}
while (m_ui->filterContainer->count())
{
delete m_ui->filterContainer->itemAt(0)->widget();
}
const ModelFilterList &modelFilterList = result.result;
int lastEventType = -1;
FilterTableEntry *lastFTW = nullptr;
QString lastAttributeType;
FilterTableEntryAttribute *lastFTEA = nullptr;
for (const FilterWorker::ModelFilter &mf : modelFilterList)
{
if (lastEventType != mf.eventType || lastEventType == -1 || !lastFTW)
{
lastEventType = mf.eventType;
lastFTW = addNewFilter(mf.eventType, mf.active);
}
if (mf.attributeType == QString())
continue;
if (lastAttributeType != mf.attributeType || lastAttributeType.isEmpty() || !lastFTEA)
{
lastAttributeType = mf.attributeType;
lastFTEA = lastFTW->addAttribute(mf.attributeType);
}
EditingModeUI *emui = lastFTEA->m_editionModeUI;
if (!emui)
continue;
emui->addAttributeContainer(mf.eventType, mf.attributeValue);
}
return true;
}
}
@@ -0,0 +1,82 @@
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <NGLLogger/INGLLogger.h>
#include <LtsSession/lts_session.h>
#include <QTimer>
#include <QJsonArray>
namespace Ui
{
class FilterWindow;
}
namespace Timeline
{
class DetailData;
class FilterTableEntry;
class FilterWorker;
class FilterWindow : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit FilterWindow(DetailData *detailData,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
LtsSession::LtsSession *session,
QWidget *parent = nullptr);
~FilterWindow();
FilterTableEntry *addNewFilter(const int eventType = -1, bool active = true);
void clearSavedFiltersList();
void updateData();
const QJsonArray exportFilter() const;
const QByteArray filterToDoc(const QJsonArray &flt);
bool loadFilters(const QJsonArray &filter);
private:
void retranslate() override;
bool apply() override;
void aboutToClose() override;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
Ui::FilterWindow *m_ui;
QTimer *updateTimer;
DetailData *m_detailData;
NGL::INGLLogger &m_logger;
LtsSession::LtsSession *m_session;
signals:
void signalConvertFilterText(const QString &);
void signalShowEvents(const QJsonArray &events);
void signalApplyFilter(const QJsonArray &filter);
void signalReloadSavedFiltersList();
void signalDeleteFilter(int);
void signalReplaceFilter(int);
void signalReplaceFilterNow(int, const QString &);
public slots:
void slotLoad();
void slotSave();
void slotUpdate();
void slotAddNewFilter();
private slots:
void slotApplyFilter();
void slotShowEvents();
};
}
@@ -0,0 +1,291 @@
#include "logger.h"
#include "FilterEquationFunctions.h"
#include "FilterValueInterpreter.h"
#include "../../detail_data.h"
#include <QString>
#include <QRect>
#include <QVariant>
namespace Timeline
{
static bool inTime(DetailData *detailData, const QVariant &value, const QString &interpreterText)
{
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
bool ok = false;
unsigned int time = value.toUInt(&ok);
if (!ok)
{
WARNING_LOG(logger) << "inTime: value error!" << value.toString();
return false;
}
InterpreterResult ir = interpretValue(detailData, DetailData::INTERPRETER_TYPE_RANGE, interpreterText);
if (ir.resultType == InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS && ir.resultList.count() == 2)
{
bool ok1 = false;
bool ok2 = false;
unsigned int t1 = ir.resultList.at(0).toUInt(&ok1);
unsigned int t2 = ir.resultList.at(1).toUInt(&ok2);
if (ok1 && ok2 && t1 <= time && t2 >= time)
{
return true;
}
}
return false;
}
static bool inArea(DetailData *detailData, const QVariant &value, const QString &interpreterText)
{
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
(void)detailData;
QStringList areaValuesList = value.toString().split(QLatin1Char('x'));
if (areaValuesList.count() != 2)
{
WARNING_LOG(logger) << "inArea: areaValuesList.count() != 2 (" << areaValuesList.count() << ")";
return false;
}
QStringList interpreterValuesList = interpreterText.split(QLatin1Char('x'));
if (interpreterValuesList.count() != 4)
{
WARNING_LOG(logger) << "inArea: interpreterValuesList.count() != 4 (" << interpreterValuesList.count() << ")";
return false;
}
bool nb = false;
int n = areaValuesList.at(0).toInt(&nb);
bool ob = false;
int o = areaValuesList.at(1).toInt(&ob);
bool n1b = false;
int n1 = interpreterValuesList.at(0).toInt(&n1b);
bool n2b = false;
int n2 = interpreterValuesList.at(1).toInt(&n2b);
bool o1b = false;
int o1 = interpreterValuesList.at(2).toInt(&o1b);
bool o2b = false;
int o2 = interpreterValuesList.at(3).toInt(&o2b);
if (!nb || !ob || !n1b || !n2b || !o1b || !o2b)
{
WARNING_LOG(logger) << "inArea: !nb || !ob || !n1b || !n2b || !o1b || !o2b";
return false;
}
QRect range;
range.adjust(o1, n1, o2, n2);
if (range.contains(o, n))
{
WARNING_LOG(logger) << "inArea: in area!";
return true;
}
WARNING_LOG(logger) << "inArea: not in area";
return false;
}
static bool inRad(DetailData *detailData, const QVariant &value, const QString &interpreterText)
{
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
(void)detailData;
QStringList radValuesList = value.toString().split(QLatin1Char('x'));
if (radValuesList.count() != 2)
{
WARNING_LOG(logger) << "inRad: radValuesList.count() != 2 (" << radValuesList.count() << ")";
return false;
}
QStringList interpreterValuesList = interpreterText.split(QLatin1Char('x'));
if (interpreterValuesList.count() != 3)
{
WARNING_LOG(logger) << "inArea: interpreterValuesList.count() != 3 (" << interpreterValuesList.count() << ")";
return false;
}
bool nb = false;
int n = radValuesList.at(0).toInt(&nb);
bool ob = false;
int o = radValuesList.at(1).toInt(&ob);
bool n1b = false;
int n1 = interpreterValuesList.at(0).toInt(&n1b);
bool o1b = false;
int o1 = interpreterValuesList.at(1).toInt(&o1b);
bool r1b = false;
int r1 = interpreterValuesList.at(2).toInt(&r1b);
if (!nb || !ob || !n1b || !o1b || !r1b)
{
WARNING_LOG(logger) << "inRad: !nb || !ob || !n1b || !o1b || !r1b";
return false;
}
QRect range;
range.adjust(o1 - r1, n1 - r1, o1 + r1, n1 + r1);
if (range.contains(o, n))
{
WARNING_LOG(logger) << "inRad: in radius!";
return true;
}
WARNING_LOG(logger) << "inRad: not in radius";
return false;
}
static bool isIntEqual(DetailData *detailData, const QVariant &value, const QString &interpreterText)
{
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
(void)detailData;
bool ok1 = false;
bool ok2 = false;
int i1 = value.toInt(&ok1);
int i2 = interpreterText.toInt(&ok2);
if (!ok1 || !ok2)
{
WARNING_LOG(logger) << "isIntEqual: STR to INT conversion error! ok1 (" << ok1 << ") ok2 (" << ok2 << ") value (" << value.toString() << ") intTxt (" << interpreterText << ")";
}
if (ok1 && ok2 && i1 == i2)
{
return true;
}
return false;
}
bool checkValue(DetailData *detailData, int attributeInterpreterType, const QVariant &value, const QString &interpreterText)
{
switch(attributeInterpreterType)
{
case DetailData::INTERPRETER_TYPE_TIME:
{
return inTime(detailData, value, interpreterText);
}
case DetailData::INTERPRETER_TYPE_AREA:
{
return inArea(detailData, value, interpreterText);
}
case DetailData::INTERPRETER_TYPE_RAD:
{
return inRad(detailData, value, interpreterText);
}
case DetailData::INTERPRETER_TYPE_STR_COMPARE:
{
if (value.toString() == interpreterText)
return true;
return false;
}
case DetailData::INTERPRETER_TYPE_ID_COMPARE:
{
bool tryIt = isIntEqual(detailData, value, interpreterText);
return tryIt;
}
default:
{
return false;
}
}
}
bool FilterEquationFunctions::checkValue(DetailData *detailData, const QString &attributeType, const QVariant &value, const QString &interpreterText)
{
int attributeInterpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType);
return checkValue(detailData, attributeInterpreterType, value, interpreterText);
}
}
@@ -0,0 +1,20 @@
#pragma once
class QVariant;
class QString;
namespace Timeline
{
class DetailData;
namespace FilterEquationFunctions
{
bool checkValue(DetailData *detailData, const QString &attributeType, const QVariant &value, const QString &interpreterText);
}
}
@@ -0,0 +1,163 @@
#include "FilterValueInterpreter.h"
#include "../../detail_data.h"
#include <QString>
#include <QStringList>
#include <QRect>
namespace Timeline
{
static InterpreterResult interpretAreaText(const QString &areaText)
{
QStringList areaList = areaText.split(QLatin1Char('x'));
if (areaList.count() != 4)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_COUNT_NOT_FOUR);
}
bool ok1 = false;
bool ok2 = false;
bool ok3 = false;
bool ok4 = false;
int n1 = areaList.at(0).toInt(&ok1);
int n2 = areaList.at(1).toInt(&ok2);
int o1 = areaList.at(2).toInt(&ok3);
int o2 = areaList.at(3).toInt(&ok4);
if (!ok1)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_N1);
}
if (!ok2)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_N2);
}
if (!ok3)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_O1);
}
if (!ok4)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_AREATEXT_CANNOT_INTERPRET_O2);
}
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
ir.resultList.append(QRect(o1, n1, o2, n2));
return ir;
}
static InterpreterResult interpretToInt(const QString &text)
{
bool ok = false;
int result = text.toInt(&ok);
if (!ok)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_TOINT_CANNOT_INTERPRET_VALUE);
}
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
ir.resultList.append(result);
return ir;
}
static InterpreterResult interpretRangeText(const QString &rangeText)
{
QStringList rangeList = rangeText.split(QLatin1Char('-'));
if (rangeList.count() != 2)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_COUNT_NOT_TWO);
}
bool ok1 = false;
bool ok2 = false;
unsigned int t1 = rangeList.at(0).toUInt(&ok1);
unsigned int t2 = rangeList.at(1).toUInt(&ok2);
if (!ok1)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_CANNOT_INTERPRET_T1);
}
if (!ok2)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_CANNOT_INTERPRET_T2);
}
if (t1 > t2)
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_RANGETEXT_BEGIN_GREATER_THAN_END);
}
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
ir.resultList.append(t1);
ir.resultList.append(t2);
return ir;
}
InterpreterResult interpretValue(DetailData *detailData, int attributeInterpreterType, const QString &value)
{
(void)detailData;
switch (attributeInterpreterType)
{
case DetailData::INTERPRETER_TYPE_ID_COMPARE:
{
return interpretToInt(value);
}
case DetailData::INTERPRETER_TYPE_RANGE:
{
return interpretRangeText(value);
}
case DetailData::INTERPRETER_TYPE_AREA:
{
return interpretAreaText(value);
}
case DetailData::INTERPRETER_TYPE_STR_COMPARE:
{
InterpreterResult ir(InterpreterResult::InterpreterResultTypes::RESULT_SUCCESS);
ir.resultList.append(value);
return ir;
}
default:
{
return InterpreterResult(InterpreterResult::InterpreterResultTypes::RESULT_ATTRIBUTE_HAS_NO_INTERPRETER);
}
}
}
InterpreterResult interpretValue(DetailData *detailData, const QString &attributeType, const QString &value)
{
int interpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType);
return interpretValue(detailData, interpreterType, value);
}
}
@@ -0,0 +1,58 @@
#pragma once
#include <QString>
#include <QVariant>
namespace Timeline
{
class DetailData;
class InterpreterResult
{
public:
enum class InterpreterResultTypes
{
RESULT_UNKNOWN,
RESULT_SUCCESS,
RESULT_ATTRIBUTE_HAS_NO_INTERPRETER,
RESULT_RANGETEXT_COUNT_NOT_TWO,
RESULT_RANGETEXT_BEGIN_GREATER_THAN_END,
RESULT_RANGETEXT_CANNOT_INTERPRET_T1,
RESULT_RANGETEXT_CANNOT_INTERPRET_T2,
RESULT_AREATEXT_COUNT_NOT_FOUR,
RESULT_AREATEXT_CANNOT_INTERPRET_N1,
RESULT_AREATEXT_CANNOT_INTERPRET_N2,
RESULT_AREATEXT_CANNOT_INTERPRET_O1,
RESULT_AREATEXT_CANNOT_INTERPRET_O2,
RESULT_TOINT_CANNOT_INTERPRET_VALUE
};
explicit InterpreterResult(const InterpreterResult::InterpreterResultTypes &res)
: resultType(res)
{
}
InterpreterResult()
: resultType(InterpreterResultTypes::RESULT_UNKNOWN)
{
}
InterpreterResultTypes resultType;
QList<QVariant> additionalInformation;
QList<QVariant> resultList;
};
InterpreterResult interpretValue(DetailData *detailData, int attributeInterpreterType, const QString &value);
InterpreterResult interpretValue(DetailData *detailData, const QString &attributeType, const QString &value);
}
@@ -0,0 +1,313 @@
#include "FilterWorker.h"
#include "InfoWindow.h"
#include "../../detail_data.h"
#include <QString>
#include <QStringList>
#include <QApplication>
#include <QJsonArray>
#include <QJsonObject>
#include <QDebug>
namespace Timeline
{
FilterWorker* FilterWorker::s_instance = nullptr;
FilterWorker* FilterWorker::getInstance()
{
if (!s_instance)
{
s_instance = new FilterWorker();
}
return s_instance;
}
FilterWorker::~FilterWorker()
{
}
void FilterWorker::deleteInstance()
{
}
FilterWorker::FilterWorker()
{
#define addErrorHandler(x,y) { FilterWorker::ErrorHandler eh; eh.errorText = y; eh.errorParamCount = eh.errorText.split(QLatin1Char('%'), QString::SkipEmptyParts).count(); m_errorHandlerLookupMap.insert(x, eh); }(void)this
addErrorHandler(GetModelFilterListResult::ERR_ATTRIBUTE_BLOCK_NOT_CLOSED, tr("Attribute block not closed: \n\'%1'"));
addErrorHandler(GetModelFilterListResult::ERR_ATTRIBUTE_HAS_NO_VALUES, tr("Attribute '%1' has no values"));
addErrorHandler(GetModelFilterListResult::ERR_COLON_MISUSE, tr("Colon misuse: \n\'%1'"));
addErrorHandler(GetModelFilterListResult::ERR_EVENT_HAS_NOT_ATTRIBUTE, tr("Attribute type '%1' does not belong to event type '%2': \n'%3'"));
addErrorHandler(GetModelFilterListResult::ERR_NO_EVENT_NAME, tr("No event name given for filter '%1'"));
addErrorHandler(GetModelFilterListResult::ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING, tr("Attribute type for '%1' does not exist"));
addErrorHandler(GetModelFilterListResult::ERR_UNKNOWN_EVENT_TYPE, tr("Event type '%1' does not exist"));
addErrorHandler(GetModelFilterListResult::ERR_VALUE_NOT_FOUND, tr("The attribute value '%1' is not a value of attribute type '%2'"));
addErrorHandler(GetModelFilterListResult::ERR_NO_VALUE_GIVEN, tr("There are no values given inside the brackets: \n'%1'"));
addErrorHandler(GetModelFilterListResult::ERR_TOO_MUCH_BRACKETS, tr("Too much brackets: \n'%1'"));
}
FilterWorker::Result makeResult(const int resultValue, const QString& additionalInformation = QString())
{
FilterWorker::Result result;
result.resultValue = resultValue;
if (!additionalInformation.isEmpty())
{
result.additionalInformation.append(additionalInformation);
}
return result;
}
FilterWorker::Result makeResult(const int resultValue, const QStringList& additionalInformationList)
{
FilterWorker::Result result;
result.resultValue = resultValue;
result.additionalInformation.append(additionalInformationList);
return result;
}
FilterWorker::GetModelFilterListResult FilterWorker::getModelFilterList(DetailData *detailData, const QJsonArray &filter, bool fromTypeSafe)
{
GetModelFilterListResult result;
if (filter.isEmpty())
{
return result;
}
for (auto i1 = filter.constBegin(); i1 != filter.constEnd(); ++i1)
{
const QJsonObject &currentFilter = (*i1).toObject();
QString eventTypeString = currentFilter[QStringLiteral("EventType")].toString();
int eventType = -1;
if (fromTypeSafe)
{
bool ok = false;
eventType = eventTypeString.toInt(&ok);
if (!ok)
{
eventType = -1;
}
}
else
{
eventType = detailData->eventTypeLookup.getEventType(eventTypeString);
}
QString eventTypeName = detailData->eventTypeLookup.getEventText(eventType);
if (!eventTypeName.isEmpty())
eventTypeString = eventTypeName;
if (eventType == -1)
{
result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_UNKNOWN_EVENT_TYPE,
eventTypeString));
continue;
}
bool active = currentFilter[QStringLiteral("Active")].toBool(false);
const QJsonArray &attributes = currentFilter[QStringLiteral("Attributes")].toArray();
if (attributes.isEmpty())
{
ModelFilter mf;
mf.eventType = eventType;
mf.attributeType = QString();
mf.active = active;
result.result.append(mf);
continue;
}
for (auto i2 = attributes.constBegin(); i2 != attributes.constEnd(); i2++)
{
const QJsonObject &attribute = (*i2).toObject();
QString attributeType = attribute[QStringLiteral("AttributeType")].toString();
if (!fromTypeSafe)
{
attributeType = detailData->attributeTypeLookup.getAttributeType(attributeType);
}
attributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
if (attributeType.isEmpty())
{
result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING,
attributeType));
continue;
}
int interpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType);
if (interpreterType == DetailData::INTERPRETER_TYPE_NONE)
{
continue;
}
const QJsonArray &attributeValues = attribute[QStringLiteral("AttributeValues")].toArray();
for (auto i3 = attributeValues.constBegin(); i3 != attributeValues.constEnd(); ++i3)
{
QString attributeValueString = (*i3).toString();
ModelFilter mf;
mf.eventType = eventType;
mf.attributeType = attributeType;
mf.active = active;
mf.attributeValue = attributeValueString;
result.result.append(mf);
}
}
}
return result;
}
bool FilterWorker::handleResultValues(const QVector<Result> &resultList, QWidget* parentWidget, bool ignoreInfos)
{
bool errorOccured = false;
InfoWindowEntryList iwel;
for (int i = 0; i < resultList.count(); i++)
{
FilterWorker::Result result = resultList.at(i);
int resultValue = result.resultValue;
if (!errorOccured && (resultValue & GetModelFilterListResult::ERR) == GetModelFilterListResult::ERR)
{
errorOccured = true;
}
if (ignoreInfos && (resultValue & GetModelFilterListResult::INFO) == GetModelFilterListResult::INFO)
{
continue;
}
InfoWindowEntry iwe;
const ErrorHandler& eh = m_errorHandlerLookupMap.value(result.resultValue);
if (!eh.isValid())
{
iwe.text = tr("Unhandled error (%1)");
iwe.infoType = InfoWindowEntry::InfoTypes::Error;
iwel.append(iwe);
continue;
}
int additionalInformationCount = result.additionalInformation.count();
QString iweText = eh.errorText;
if (eh.errorParamCount)
{
for (int i2 = 0; i2 < eh.errorParamCount; i2++)
{
if (additionalInformationCount >= eh.errorParamCount)
{
iweText = iweText.arg(result.additionalInformation.at(i2));
}
else
{
iweText = iweText.arg(QStringLiteral("???"));
}
}
}
iwe.text = iweText;
iwel.append(iwe);
}
if (iwel.count())
{
InfoWindow* iw = new InfoWindow(iwel, parentWidget);
iw->show();
}
return !errorOccured;
}
}
@@ -0,0 +1,113 @@
#pragma once
#include <QVector>
#include <QString>
#include <QWidget>
#include <QMap>
namespace Timeline
{
class DetailData;
class FilterWorker : public QObject
{
Q_OBJECT
private:
FilterWorker();
~FilterWorker();
static FilterWorker* s_instance;
public:
static FilterWorker* getInstance();
static void deleteInstance();
struct ModelFilter
{
int eventType = -1;
QString attributeType;
bool active = false;
QString attributeValue;
};
struct Result
{
int resultValue = -1;
QStringList additionalInformation;
};
struct GetModelFilterListResult
{
enum ResultType
{
ERR = 0x80,
WARN = 0x40,
INFO = 0x20,
};
enum ResultValues
{
ERR_NO_EVENT_NAME = ERR | 0,
ERR_COLON_MISUSE = ERR | 1,
ERR_UNKNOWN_EVENT_TYPE = ERR | 2,
ERR_ATTRIBUTE_HAS_NO_VALUES = ERR | 3,
ERR_ATTRIBUTE_BLOCK_NOT_CLOSED = ERR | 4,
ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING = ERR | 5,
ERR_EVENT_HAS_NOT_ATTRIBUTE = ERR | 7,
ERR_VALUE_NOT_FOUND = ERR | 8,
ERR_NO_VALUE_GIVEN = ERR | 9,
ERR_TOO_MUCH_BRACKETS = ERR | 10,
};
QVector<Result> resultValueList;
QVector<ModelFilter> result;
};
static GetModelFilterListResult getModelFilterList(DetailData *detailData, const QJsonArray &filter, bool fromTypeSafe = false);
bool handleResultValues(const QVector<Result> &resultList, QWidget* parentWidget = nullptr, bool ignoreInfos = false);
private:
class ErrorHandler
{
public:
ErrorHandler(const QString& errorText = QString(), const int errorParamCount = 0)
: errorText(errorText)
, errorParamCount(errorParamCount)
{
}
bool isValid() const
{
if (errorText.isEmpty() && !errorParamCount)
return false;
return true;
}
QString errorText;
int errorParamCount;
};
using ErrorHandlerLookupMap = QMap<int, ErrorHandler>;
ErrorHandlerLookupMap m_errorHandlerLookupMap;
};
using ModelFilterList = QVector<FilterWorker::ModelFilter>;
}
@@ -0,0 +1,128 @@
#include "InfoWindow.h"
#include <QHBoxLayout>
#include <QMessageBox>
namespace Timeline
{
InfoWindow::InfoWindow(const InfoWindowEntryList &infoWindowEntryList, QWidget* parent)
: QDialog(parent)
, infoWindowEntryList(infoWindowEntryList)
, mainLayout(new QVBoxLayout())
, pbPrev(new QPushButton(tr("< Previous")))
, lbIndicator(new QLabel())
, pbNext(new QPushButton(tr("Next >")))
, pbOK(new QPushButton(tr("OK")))
, teText(new QTextEdit(tr("Missing Message")))
, listPosition(-1)
{
if (!infoWindowEntryList.count())
{
return;
}
connect(pbPrev, &QPushButton::clicked, this, &InfoWindow::slotPrev);
connect(pbNext, &QPushButton::clicked, this, &InfoWindow::slotNext);
connect(pbOK , &QPushButton::clicked, this, &InfoWindow::deleteLater);
QHBoxLayout* topButtonsLayout = new QHBoxLayout();
pbPrev->setEnabled(false);
topButtonsLayout->addWidget(pbPrev);
topButtonsLayout->addWidget(lbIndicator);
topButtonsLayout->addWidget(pbNext);
pbNext->setEnabled(false);
QWidget* topButtonsWidget = new QWidget();
topButtonsWidget->setLayout(topButtonsLayout);
mainLayout->addWidget(topButtonsWidget);
mainLayout->addWidget(teText);
QHBoxLayout* bottomButtonsLayout = new QHBoxLayout();
bottomButtonsLayout->addWidget(pbOK);
QWidget* bottomButtonsWidget = new QWidget();
bottomButtonsWidget->setLayout(bottomButtonsLayout);
mainLayout->addWidget(bottomButtonsWidget);
slotNext();
this->setLayout(mainLayout);
}
void InfoWindow::checkNavigationButtons(int newPosition)
{
int listCount = infoWindowEntryList.count();
if (newPosition -1 >= 0)
{
pbPrev->setEnabled(true);
}
else
{
pbPrev->setEnabled(false);
}
if (newPosition +2 > listCount)
{
pbNext->setEnabled(false);
}
else
{
pbNext->setEnabled(true);
}
}
void InfoWindow::slotPrev()
{
int listCount = infoWindowEntryList.count();
int prevListPosition = listPosition - 1 ;
checkNavigationButtons(prevListPosition);
if (prevListPosition >= 0 && prevListPosition < listCount)
{
teText->setText(infoWindowEntryList.at(prevListPosition).text);
QString indicatorString = QStringLiteral("%1/%2");
lbIndicator->setText(indicatorString.arg(prevListPosition + 1 ).arg(listCount));
listPosition = prevListPosition;
}
}
void InfoWindow::slotNext()
{
int listCount = infoWindowEntryList.count();
int nextListPosition = listPosition + 1 ;
checkNavigationButtons(nextListPosition);
if (nextListPosition >= 0 && nextListPosition < listCount)
{
teText->setText(infoWindowEntryList.at(nextListPosition).text);
QString indicatorString = QStringLiteral("%1/%2");
lbIndicator->setText(indicatorString.arg(nextListPosition + 1 ).arg(listCount));
listPosition = nextListPosition;
}
}
}
@@ -0,0 +1,61 @@
#pragma once
#include <QDialog>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QLabel>
namespace Timeline
{
struct InfoWindowEntry
{
enum class InfoTypes
{
Error,
Info,
Warning
};
QString title;
QString text;
InfoTypes infoType = InfoTypes::Info;
};
typedef QVector<InfoWindowEntry> InfoWindowEntryList;
class InfoWindow : public QDialog
{
Q_OBJECT
public:
InfoWindow(const InfoWindowEntryList &infoWindowEntryList, QWidget* parent = nullptr);
~InfoWindow() = default;
private:
InfoWindowEntryList infoWindowEntryList;
QVBoxLayout* mainLayout;
QPushButton* pbPrev;
QLabel* lbIndicator;
QPushButton* pbNext;
QPushButton* pbOK;
QTextEdit* teText;
int listPosition;
void checkNavigationButtons(int newPosition);
public slots:
void slotPrev();
void slotNext();
};
}
@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FilterWindow</class>
<widget class="QWidget" name="FilterWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>628</width>
<height>393</height>
</rect>
</property>
<property name="windowTitle">
<string>Filter Table</string>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Closing this window will reset all filters for the timeline.</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaContent">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>610</width>
<height>358</height>
</rect>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QVBoxLayout" name="filterContainer"/>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,38 @@
#include "AbstractAttributeWidget.h"
#include <QHBoxLayout>
#include <QPushButton>
namespace Timeline
{
AbstractAttributeWidget::AbstractAttributeWidget(QWidget *parent)
: QWidget(parent)
, m_abstractMainLayout(new QHBoxLayout(this))
{
QPushButton *pbDelete(new QPushButton(QStringLiteral("-")));
pbDelete->setPalette(QPalette(QColor("red")));
pbDelete->setToolTip(tr("Delete this value"));
m_abstractMainLayout->addWidget(pbDelete);
connect(pbDelete, &QPushButton::clicked, this, &AbstractAttributeWidget::slotDelete);
}
void AbstractAttributeWidget::slotDelete()
{
emit deleteClicked();
deleteLater();
}
void AbstractAttributeWidget::addCustomWidget(QWidget* widget)
{
m_abstractMainLayout->insertWidget(0, widget, 1, Qt::AlignLeft);
}
}
@@ -0,0 +1,36 @@
#pragma once
#include <QWidget>
class QHBoxLayout;
namespace Timeline
{
class DetailData;
class AbstractAttributeWidget : public QWidget
{
Q_OBJECT
public:
explicit AbstractAttributeWidget(QWidget *parent = nullptr);
virtual QString filterText(bool typeSafe = false) const = 0;
virtual void updateData(DetailData *detailData) = 0;
protected:
void addCustomWidget(QWidget* widget);
protected:
QHBoxLayout *m_abstractMainLayout;
private slots:
void slotDelete();
signals:
void signalChanges();
void deleteClicked();
};
}
@@ -0,0 +1,71 @@
#include "AreaWidget.h"
#include <QGridLayout>
#include <QSpinBox>
#include <QWidget>
namespace Timeline
{
AreaWidget::AreaWidget(int n1, int n2, int o1, int o2, QWidget *parent)
: AbstractAttributeWidget(parent)
, sbN1(new QSpinBox())
, sbN2(new QSpinBox())
, sbO1(new QSpinBox())
, sbO2(new QSpinBox())
{
connect(sbN1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
connect(sbN2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
connect(sbO1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
connect(sbO2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &AreaWidget::signalChanges);
QString sbNPrefix = tr("N ");
QString sbOPrefix = tr("O ");
sbN1->setPrefix(sbNPrefix);
sbN2->setPrefix(sbNPrefix);
sbO1->setPrefix(sbOPrefix);
sbO2->setPrefix(sbOPrefix);
sbN1->setRange(n1, n2);
sbN2->setRange(n1, n2);
sbO1->setRange(o1, o2);
sbO2->setRange(o1, o2);
sbN1->setValue(n1);
sbN2->setValue(n2);
sbO1->setValue(o1);
sbO2->setValue(o2);
QGridLayout* mainLayout = new QGridLayout();
mainLayout->addWidget(sbN1, 0, 1);
mainLayout->addWidget(sbN2, 2, 1);
mainLayout->addWidget(sbO1, 1, 0);
mainLayout->addWidget(sbO2, 1, 2);
QWidget* mainLayoutWidget = new QWidget();
mainLayoutWidget->setLayout(mainLayout);
this->addCustomWidget(mainLayoutWidget);
}
QString AreaWidget::filterText(bool typeSafe) const
{
Q_UNUSED(typeSafe);
return QStringLiteral("%1x%2x%3x%4").arg(sbN1->cleanText(), sbN2->cleanText(), sbO1->cleanText(), sbO2->cleanText());
}
void AreaWidget::updateData(DetailData *detailData)
{
Q_UNUSED(detailData);
}
}
@@ -0,0 +1,30 @@
#pragma once
#include "AbstractAttributeWidget.h"
class QSpinBox;
namespace Timeline
{
class AreaWidget : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit AreaWidget(int n1, int n2, int o1, int o2, QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *detailData) override;
private:
QSpinBox* sbN1;
QSpinBox* sbN2;
QSpinBox* sbO1;
QSpinBox* sbO2;
};
}
@@ -0,0 +1,67 @@
#include "CheckBoxWidget.h"
#include "../../detail_data.h"
#include <QCheckBox>
namespace Timeline
{
CheckBoxWidget::CheckBoxWidget(DetailData *detailData, const QString &attributeType, const QString &initialValue, QWidget* parent)
: AbstractAttributeWidget(parent)
, cbCheck(new QCheckBox(this))
{
connect(cbCheck, &QCheckBox::stateChanged, this, &CheckBoxWidget::signalChanges);
trueValue = detailData->attributeValueLookup.getValueStringFromValueId(attributeType, 1);
falseValue = detailData->attributeValueLookup.getValueStringFromValueId(attributeType, 0);
cbCheck->setText(trueValue);
addCustomWidget(cbCheck);
if (initialValue.isEmpty())
return;
cbCheck->setChecked(initialValue != QStringLiteral("0"));
}
void CheckBoxWidget::setText(const QString &text)
{
cbCheck->setText(text);
}
QString CheckBoxWidget::filterText(bool typeSafe) const
{
QString filterText;
if (cbCheck->isChecked())
{
if (typeSafe)
filterText += QStringLiteral("1");
else
filterText += trueValue;
}
else
{
if (typeSafe)
filterText += QStringLiteral("0");
else
filterText += falseValue;
}
return filterText;
}
void CheckBoxWidget::updateData(DetailData *)
{
}
}
@@ -0,0 +1,31 @@
#pragma once
#include "AbstractAttributeWidget.h"
#include "../../detail_data.h"
class QCheckBox;
namespace Timeline
{
class CheckBoxWidget : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit CheckBoxWidget(DetailData *detailData, const QString &attributeType, const QString &initialValue, QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *) override;
void setText(const QString &text);
private:
QCheckBox* cbCheck;
QString trueValue;
QString falseValue;
};
}
@@ -0,0 +1,102 @@
#include "ComboBox.h"
#include "logger.h"
#include <QComboBox>
namespace Timeline
{
ComboBox::ComboBox(DetailData *detailData, const QString &attributeType, int eventType, const QString &initialValue, QWidget* parent)
: AbstractAttributeWidget(parent)
, m_cbValues(new QComboBox())
, m_eventType(eventType)
, m_logger(getLogger("EventFilter.ComboBox"))
{
connect(m_cbValues, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ComboBox::signalChanges);
addCustomWidget(m_cbValues);
m_concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
updateData(detailData);
if (initialValue.isEmpty())
return;
bool k = false;
int initialValueKey = initialValue.toInt(&k);
if (initialValueKey < 0 || !k)
{
WARNING_LOG(m_logger) << "ComboBox::c_tor: initialValueKey < 0 (" << initialValueKey << ")" << "initialValue: " << initialValue;
return;
}
m_cbValues->setCurrentIndex(m_cbValues->findData(initialValueKey, Qt::UserRole));
}
void ComboBox::updateData(DetailData *detailData)
{
int lastSelectedKey = -1;
if (m_cbValues->currentIndex() > 0)
lastSelectedKey = m_cbValues->itemData(m_cbValues->currentIndex()).toInt();
QSignalBlocker blocker(m_cbValues);
m_cbValues->clear();
m_avm = detailData->m_attributeValueLookupDtc.getAttributeValueMap(m_eventType, m_concreteAttributeType);
if (m_avm.isEmpty())
m_avm = detailData->attributeValueLookup.getAttributeValueMap(m_concreteAttributeType);
for (auto i = m_avm.constBegin(); i != m_avm.constEnd(); ++i)
{
m_cbValues->addItem(i.value()
#ifdef DEBUG
+ " (" + QString::number(i.key()) + ")"
#endif
, i.key());
}
if (lastSelectedKey < 0)
{
m_cbValues->setCurrentIndex(0);
return;
}
m_cbValues->setCurrentIndex(m_cbValues->findData(lastSelectedKey, Qt::UserRole));
DEBUG_LOG(m_logger) << "ComboBox: no initial item index found for value id" << lastSelectedKey;
}
QString ComboBox::filterText(bool typeSafe) const
{
QString resultFilterText;
bool ok = false;
int key = m_cbValues->itemData(m_cbValues->currentIndex()).toInt(&ok);
if (!ok)
{
return resultFilterText;
}
if (typeSafe)
resultFilterText = QString::number(key);
else
resultFilterText = m_avm.value(key);
return resultFilterText;
}
}
@@ -0,0 +1,36 @@
#pragma once
#include "AbstractAttributeWidget.h"
#include "../../detail_data.h"
#include <NGLLogger/INGLLogger.h>
class QComboBox;
namespace Timeline
{
class ComboBox : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit ComboBox(DetailData *detailData, const QString &attributeType,
int eventType, const QString &initialValue, QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *detailData) override;
private:
QComboBox *m_cbValues;
int m_eventType;
QString m_concreteAttributeType;
AttributeValueMap m_avm;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,93 @@
#include "DefaultRangeWidget.h"
#include "logger.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QWidget>
namespace Timeline
{
DefaultRangeWidget::DefaultRangeWidget(unsigned int min, unsigned int max, const QString &prefix, const QString &suffix, const QString &initialValue, QWidget *parent)
: AbstractAttributeWidget(parent)
, box1(new QSpinBox())
, box2(new QSpinBox())
, m_logger(getLogger("EventFilter.Widgets.DefaultRangeWidget"))
{
connect(box1, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &DefaultRangeWidget::signalChanges);
connect(box2, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &DefaultRangeWidget::signalChanges);
box1->setRange(min, max);
box2->setRange(min, max);
box1->setPrefix(prefix);
box2->setPrefix(prefix);
box1->setSuffix(suffix);
box2->setSuffix(suffix);
box1->setValue(min);
box2->setValue(max);
QHBoxLayout* mainLayout = new QHBoxLayout();
mainLayout->addWidget(new QLabel(tr("between")));
mainLayout->addWidget(box1);
mainLayout->addWidget(new QLabel(tr("and")));
mainLayout->addWidget(box2);
QWidget* mainLayoutWidget = new QWidget();
mainLayoutWidget->setLayout(mainLayout);
this->addCustomWidget(mainLayoutWidget);
box1->setFocus();
if (initialValue.length())
{
QStringList valueList = initialValue.split(QLatin1Char('-'), QString::SkipEmptyParts);
if (valueList.count() != 2)
{
WARNING_LOG(m_logger) << "DefaultRangeWidget: invalid initial value '" << initialValue << "'";
return;
}
bool k1 = false;
bool k2 = false;
unsigned int val1 = valueList.at(0).toUInt(&k1);
unsigned int val2 = valueList.at(1).toUInt(&k2);
if (!k1 || !k2)
{
WARNING_LOG(m_logger) << "DefaultRangeWidget: initial value is not numeric '" << initialValue << "'";
return;
}
box1->setValue(val1);
box2->setValue(val2);
}
}
QString DefaultRangeWidget::filterText(bool typeSafe) const
{
Q_UNUSED(typeSafe);
return QStringLiteral("%1 - %2").arg(box1->value(), box2->value());
}
void DefaultRangeWidget::updateData(DetailData *detailData)
{
Q_UNUSED(detailData);
}
}
@@ -0,0 +1,38 @@
#pragma once
#include "AbstractAttributeWidget.h"
#include <NGLLogger/INGLLogger.h>
class QHBoxLayout;
class QSpinBox;
namespace Timeline
{
class DefaultRangeWidget : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit DefaultRangeWidget(unsigned int min,
unsigned int max,
const QString &prefix,
const QString &suffix,
const QString &initialValue = QString(),
QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *detailData) override;
private:
QSpinBox* box1;
QSpinBox* box2;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,64 @@
#include "RadiusWidget.h"
#include <QGridLayout>
#include <QSpinBox>
#include <QWidget>
namespace Timeline
{
RadiusWidget::RadiusWidget(int n1, int n2, int o1, int o2, int radius, QWidget *parent)
: AbstractAttributeWidget(parent)
, sbN(new QSpinBox(this))
, sbO(new QSpinBox(this))
, sbR(new QSpinBox(this))
{
Q_ASSERT(false);
QString sbNPrefix = tr("N ");
QString sbOPrefix = tr("O ");
QString sbRPrefix = tr("radius of ");
sbN->setPrefix(sbNPrefix);
sbO->setPrefix(sbOPrefix);
sbR->setPrefix(sbRPrefix);
sbN->setRange(n1, n2);
sbO->setRange(o1, o2);
sbR->setRange(0, 9999);
sbN->setValue(n1);
sbO->setValue(o1);
sbR->setValue(radius);
QGridLayout* mainLayout = new QGridLayout();
mainLayout->addWidget(sbN, 0, 0);
mainLayout->addWidget(sbR, 0, 1);
mainLayout->addWidget(sbO, 0, 2);
QWidget* mainLayoutWidget = new QWidget();
mainLayoutWidget->setLayout(mainLayout);
addCustomWidget(mainLayoutWidget);
}
QString RadiusWidget::filterText(bool typeSafe) const
{
Q_UNUSED(typeSafe);
return QStringLiteral("%1x%2x%3").arg(sbN->cleanText(), sbO->cleanText(), sbR->cleanText());
}
void RadiusWidget::updateData(DetailData *)
{
}
}
@@ -0,0 +1,29 @@
#pragma once
#include "AbstractAttributeWidget.h"
class QSpinBox;
namespace Timeline
{
class RadiusWidget : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit RadiusWidget(int n1, int n2, int o1, int o2, int radius, QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *detailData) override;
private:
QSpinBox* sbN;
QSpinBox* sbO;
QSpinBox* sbR;
};
}
@@ -0,0 +1,103 @@
#include "logger.h"
#include "TimeRangeWidget.h"
#include "../../detail_data.h"
#include <LtsWidgets/lts_date_time_edit.h>
#include <QHBoxLayout>
#include <QLabel>
#include <QDateTime>
namespace Timeline
{
TimeRangeWidget::TimeRangeWidget(DetailData *detailData, const QString &initialValue, QWidget *parent)
: AbstractAttributeWidget(parent)
, m_logger(getLogger("EventFilter.Widgets.TimeRangeWidget"))
, m_edit1(new LtsWidgets::LtsDateTimeEdit(this))
, m_edit2(new LtsWidgets::LtsDateTimeEdit(this))
{
connect(m_edit1, &LtsWidgets::LtsDateTimeEdit::dateTimeChanged, this, &TimeRangeWidget::signalChanges);
connect(m_edit2, &LtsWidgets::LtsDateTimeEdit::dateTimeChanged, this, &TimeRangeWidget::signalChanges);
QHBoxLayout* mainLayout = new QHBoxLayout();
mainLayout->addWidget(new QLabel(tr("between")));
mainLayout->addWidget(m_edit1);
mainLayout->addWidget(new QLabel(tr("and")));
mainLayout->addWidget(m_edit2);
QWidget* mainLayoutWidget = new QWidget();
mainLayoutWidget->setLayout(mainLayout);
addCustomWidget(mainLayoutWidget);
m_edit1->setFocus();
updateData(detailData);
if (initialValue.isEmpty())
return;
const auto initialTimeRange(initialValue.splitRef(QLatin1Char('-'), QString::SkipEmptyParts));
if (initialTimeRange.count() != 2)
{
WARNING_LOG(m_logger) << "invalid initial time range value: " << initialValue;
return;
}
bool k = false;
qint64 time = initialTimeRange.at(0).toInt(&k);
time *= 1000;
if (!k)
WARNING_LOG(m_logger) << "invalid initial time range start value: " << initialTimeRange.at(0).toString();
else
m_edit1->setMsecsSinceEpoch(time);
time = initialTimeRange.at(1).toInt(&k);
time *= 1000;
if (!k)
WARNING_LOG(m_logger) << "invalid initial time range start value: " << initialTimeRange.at(1).toString();
else
m_edit2->setMsecsSinceEpoch(time);
}
QString TimeRangeWidget::filterText(bool typeSafe) const
{
(void)typeSafe;
QString filterText;
filterText += QString::number(m_edit1->msecsSinceEpoch() / 1000 );
filterText += QLatin1Char('-');
filterText += QString::number(m_edit2->msecsSinceEpoch() / 1000 );
return filterText;
}
void TimeRangeWidget::updateData(DetailData *detailData)
{
LtsSession::LtsSession *session = detailData->session();
m_edit1->setMsecsSinceEpoch(session->partitionTime() - 60 * 1000 );
m_edit2->setMsecsSinceEpoch(session->partitionTime());
}
}
@@ -0,0 +1,35 @@
#pragma once
#include "AbstractAttributeWidget.h"
#include <NGLLogger/INGLLogger.h>
namespace LtsWidgets
{
class LtsDateTimeEdit;
}
namespace Timeline
{
class TimeRangeWidget : public AbstractAttributeWidget
{
Q_OBJECT
public:
explicit TimeRangeWidget(DetailData *detailData, const QString &initialValue, QWidget *parent = nullptr);
QString filterText(bool typeSafe = false) const override;
void updateData(DetailData *detailData) override;
private:
NGL::INGLLogger &m_logger;
public:
LtsWidgets::LtsDateTimeEdit *m_edit1;
LtsWidgets::LtsDateTimeEdit *m_edit2;
};
}
@@ -0,0 +1,296 @@
#include "attribute_value_lookup.h"
#include <AudioVideoManagement/avm_dtc.h>
#include <AudioVideoManagement/stream_name_mapping.h>
#include <InfrastructureManagement/ism_dtc.h>
#include <OperatorManagement/opm_dtc.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ProjectDataManagement/pdm_dtc.h>
#include <OperatorManagement/opm_translation.h>
#include <ParticipantManagement/ppm_translation.h>
#include <QVector>
namespace Timeline
{
AttributeValueMap AvmChargeType::getAttributeValueMap(int eventType) const
{
if (!m_dtc)
return {};
using namespace ProjectDataManagement;
QVector<ChargeType> charges;
switch (eventType)
{
case EventType::Hit:
case EventType::WeaponAssignment:
case EventType::FireEvent:
charges = m_dtc->chargesForGearClass(GearClass::DuelSim);
break;
case EventType::HitBuilding:
charges = m_dtc->chargesForGearClass(GearClass::DuelSim);
Q_FALLTHROUGH();
case EventType::HitEffectSimulation:
charges += m_dtc->chargesForGearClass(GearClass::Artillery);
charges += m_dtc->chargesForGearClass(GearClass::Mortar);
charges += m_dtc->chargesForGearClass(GearClass::Geopairing);
charges += m_dtc->chargesForGearClass(GearClass::AirSupport);
charges += m_dtc->chargesForGearClass(GearClass::MineArea);
charges += m_dtc->chargesForGearClass(GearClass::Biological);
charges += m_dtc->chargesForGearClass(GearClass::Chemical);
break;
case EventType::HitB:
charges = m_dtc->chargesForGearClass(GearClass::Biological);
break;
case EventType::HitC:
charges = m_dtc->chargesForGearClass(GearClass::Chemical);
break;
case EventType::BCContamination:
charges = m_dtc->chargesForGearClass(GearClass::Biological);
charges += m_dtc->chargesForGearClass(GearClass::Chemical);
break;
case EventType::HitMine:
case EventType::EnterMineArea:
case EventType::LeaveMineArea:
case EventType::MineArea:
charges = m_dtc->chargesForGearClass(GearClass::MineArea);
break;
}
Q_ASSERT(!charges.isEmpty());
AttributeValueMap ret;
for (const ChargeType &data : qAsConst(charges))
ret.insert(data.id(), m_dtc->trChargeTypeShortName(data.id()));
return ret;
}
QString AvmChargeType::getValueStringFromValueId(int attributeValueId) const
{
if (!m_dtc)
return {};
return m_dtc->trChargeTypeShortName(attributeValueId);
}
AttributeValueMap AvmGearType::getAttributeValueMap(int eventType) const
{
using namespace ProjectDataManagement;
if (eventType != EventType_def::WeaponAssignment &&
eventType != EventType_def::FireEvent)
{
Q_ASSERT(false);
return {};
}
if (!m_dtc)
return {};
const auto gearTypes = m_dtc->gearTypes();
AttributeValueMap ret;
for (const auto &data : gearTypes)
{
if (data.gearClassId() == GearClass::DuelSim &&
data.tasCode() != 0)
ret.insert(data.id(), m_dtc->trGearTypeName(data.id()));
}
return ret;
}
QString AvmGearType::getValueStringFromValueId(int attributeValueId) const
{
if (!m_dtc)
return {};
return m_dtc->trGearTypeName(attributeValueId);
}
AttributeValueMap AvmParty::getAttributeValueMap(int eventType) const
{
Q_UNUSED(eventType);
using namespace ParticipantManagement;
if (!m_dtc)
return {};
const auto parties = m_dtc->partys();
AttributeValueMap ret;
for (const auto &data : parties)
ret.insert(data.id(), trPartyName(data.name()));
return ret;
}
QString AvmParty::getValueStringFromValueId(int attributeValueId) const
{
using namespace ParticipantManagement;
if (!m_dtc)
return {};
return trPartyName(m_dtc->party(attributeValueId).name());
}
AttributeValueMap AvmEquipmentNumber::getAttributeValueMap(int eventType) const
{
Q_UNUSED(eventType);
using namespace ParticipantManagement;
if (!m_dtc)
return {};
AttributeValueMap ret;
auto cb = [&ret](const ParticipantManagement::Participant & p) -> void
{
if (!p.equipmentNumber().is_set())
return;
const auto equipNo = p.equipmentNumber().get();
ret.insert(equipNo, QString::number(equipNo));
};
m_dtc->participants(cb);
return ret;
}
QString AvmEquipmentNumber::getValueStringFromValueId(int attributeValueId) const
{
if (!m_dtc)
return {};
auto ret = m_dtc->participant(attributeValueId).equipmentNumber();
return ret.is_set() ? QString::number(ret.get()) : QString();
}
AttributeValueMap AvmOperator::getAttributeValueMap(int eventType) const
{
Q_UNUSED(eventType);
using namespace OperatorManagement;
if (!m_dtc)
return {};
const auto users = m_dtc->users();
AttributeValueMap ret;
for (const auto &data : users)
ret.insert(data.id(), QString::fromStdString(data.name()));
ret.insert(0, QObject::tr("EXCON"));
return ret;
}
QString AvmOperator::getValueStringFromValueId(int attributeValueId) const
{
if (attributeValueId == 0)
return QObject::tr("EXCON");
if (!m_dtc)
return {};
return QString::fromStdString(m_dtc->user(attributeValueId).name());
}
AttributeValueMap AvmBuilding::getAttributeValueMap(int eventType) const
{
Q_UNUSED(eventType);
if (!m_dtc)
return {};
AttributeValueMap ret;
auto cb = [this, &ret](const InfrastructureManagement::MainStructureElement &mse) -> void
{
if (mse.structureElementTypeId() != InfrastructureManagement::StructureElementType::Building)
return;
ret.insert(mse.id(), m_dtc->getBuildingDisplayName(mse));
};
m_dtc->mainStructureElements(cb);
return ret;
}
QString AvmBuilding::getValueStringFromValueId(int attributeValueId) const
{
if (!m_dtc)
return {};
return m_dtc->getBuildingDisplayName(attributeValueId);
}
AvmStreamName::AvmStreamName(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc)
: m_dtc(dtc)
, m_snm(AudioVideoManagement::StreamNameMapping::create(m_dtc.get()))
{}
AvmStreamName::~AvmStreamName() = default;
AttributeValueMap AvmStreamName::getAttributeValueMap(int eventType) const
{
AttributeValueMap ret;
if (!m_dtc)
return ret;
switch (eventType)
{
case ProjectDataManagement::EventType::RadioCnr:
{
auto cb = [&ret](const AudioVideoManagement::CnrConfig &cnrConfig) -> void
{
ret.insert(cnrConfig.id(), QString::fromStdString(cnrConfig.radioCircuit()));
};
m_dtc->cnrConfigs(cb);
break;
}
case ProjectDataManagement::EventType::RadioTvc:
{
auto cb = [&ret](const AudioVideoManagement::TvcConfig &tvcConfig) -> void
{
ret.insert(tvcConfig.id(), QString::fromStdString(tvcConfig.radioCircuit()));
};
m_dtc->tvcConfigs(cb);
break;
}
case ProjectDataManagement::EventType::CameraVideo:
{
auto cb = [this, &ret](const AudioVideoManagement::Stream &stream) -> void
{
if (stream.mountingPointId() == 0 ||
stream.type() != AudioVideoManagement::StreamType::Video)
return;
ret.insert(stream.id(), m_snm->displayName(stream.mountingPointId()));
};
m_dtc->streams(cb);
break;
}
default:
break;
}
return ret;
}
QString AvmStreamName::getValueStringFromValueId(int attributeValueId) const
{
if (!m_dtc)
return {};
return QString::fromStdString(m_dtc->stream(attributeValueId).name());
}
}
@@ -0,0 +1,131 @@
#pragma once
#include <QMap>
#include <QString>
#include <memory>
namespace AudioVideoManagement
{
class StreamNameMapping;
namespace Interface
{
class Dtc;
}
}
namespace InfrastructureManagement
{
namespace Interface
{
class Dtc;
}
}
namespace OperatorManagement
{
namespace Interface
{
class Dtc;
}
}
namespace ParticipantManagement
{
namespace Interface
{
class Dtc;
}
}
namespace ProjectDataManagement
{
namespace Interface
{
class Dtc;
}
}
namespace Timeline
{
using AttributeValueMap = QMap<int, QString>;
using AtributeValueLookupMap = QMap<QString, AttributeValueMap>;
class AttributeValueLookupProvider
{
public:
virtual ~AttributeValueLookupProvider() = default;
virtual AttributeValueMap getAttributeValueMap(int eventType) const = 0;
virtual QString getValueStringFromValueId(int attributeValueId) const = 0;
};
class AvmChargeType final : public AttributeValueLookupProvider
{
public:
explicit AvmChargeType(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_dtc;
};
class AvmGearType final : public AttributeValueLookupProvider
{
public:
explicit AvmGearType(const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_dtc;
};
class AvmParty final : public AttributeValueLookupProvider
{
public:
explicit AvmParty(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
};
class AvmEquipmentNumber final : public AttributeValueLookupProvider
{
public:
explicit AvmEquipmentNumber(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_dtc;
};
class AvmOperator final : public AttributeValueLookupProvider
{
public:
explicit AvmOperator(const std::shared_ptr<OperatorManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<OperatorManagement::Interface::Dtc> m_dtc;
};
class AvmBuilding final : public AttributeValueLookupProvider
{
public:
explicit AvmBuilding(const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &dtc) : m_dtc(dtc) {}
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_dtc;
};
class AvmStreamName final : public AttributeValueLookupProvider
{
public:
explicit AvmStreamName(const std::shared_ptr<AudioVideoManagement::Interface::Dtc> &dtc);
~AvmStreamName();
AttributeValueMap getAttributeValueMap(int eventType) const override;
QString getValueStringFromValueId(int attributeValueId) const override;
private:
std::shared_ptr<AudioVideoManagement::Interface::Dtc> m_dtc;
std::shared_ptr<AudioVideoManagement::StreamNameMapping> m_snm;
};
}
@@ -0,0 +1,857 @@
#include "detail_data.h"
#include "logger.h"
#include "tln_legend.h"
#include "attribute_value_lookup.h"
#include <LtsTimelineClassic/Event.h>
#include <LtsWidgets/lts_date_time_edit.h>
#include <LtsSession/lts_session.h>
#include <LtsUtilsSettings/settings.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/MarkerManagement/mrk_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/OperatorManagement/opm_data_plugin_interface.h>
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Services/ExerciseEventManagement/eem_enums.hpp>
#include <Services/ExerciseEventManagement/eem_translation.h>
#include <Services/ProjectDataManagement/pdm_translation.h>
#include <Services/AreaEffectSimulation/aes_translation.h>
#include <Services/MarkerManagement/mrk_translation.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QVariant>
namespace Timeline
{
static inline QString removeSpaces(const QString &str)
{
QString ret;
ret.reserve(str.size());
for (const QChar c : str)
{
if (!c.isSpace())
ret += c;
}
return ret;
}
DetailData::DetailData(LtsSession::LtsSession *session, QObject *parent)
: QObject(parent)
, m_session(session)
, __already_populated__(false)
, m_logger(getLogger("DetailData"))
{
populate();
}
void DetailData::addRedirectedAttributeType(const QString &newAttributeTypeId, const QString &attributeText, const QString &redirectToAttributeTypeId)
{
attributeTypeLookup.addAttributeText(newAttributeTypeId, attributeText);
attributeRedirectionLookup.addRedirection(newAttributeTypeId, redirectToAttributeTypeId);
}
void DetailData::addAttributeType(const QString &attributeTypeId, const QString &attributeText, const int uiTypeId, const int interpreterTypeId)
{
attributeTypeLookup.addAttributeText(attributeTypeId, attributeText);
attributeUITypeLookup.addUITypeToAttribute(attributeTypeId, uiTypeId);
attributeInterpreterLookup.addInterpreterTypeToAttribute(attributeTypeId, interpreterTypeId);
}
void DetailData::addEventType(int eventTypeId, const QString &eventTypeString)
{
eventTypeLookup.addEventType(eventTypeId, eventTypeString);
attributeEventLookup.addAttributesToEvent(eventTypeId, {QStringLiteral("TimeRange")});
}
void DetailData::addEventType(const ProjectDataManagement::EventType &eventType)
{
addEventType(eventType.underlying(), ProjectDataManagement::toString(eventType));
}
void DetailData::populate()
{
if (__already_populated__)
return;
__already_populated__ = true;
addEventType(0, tr("General"));
addEventType(markerTypeId, tr("Marker"));
attributeEventLookup.addAttributesToEvent(markerTypeId, {QStringLiteral("MarkerName"),
QStringLiteral("MarkerNote"),
QStringLiteral("Operator"),
QStringLiteral("MarkerOffset"),
QStringLiteral("IsSituationType"),
QStringLiteral("IsVideoType"),
QStringLiteral("IsAudioType")});
using namespace ProjectDataManagement;
const auto possibleEventTypes = TimelineLegendDialog::possibleEvents();
for (const auto eventType : possibleEventTypes)
{
switch (eventType.underlying())
{
case EventType::Hit:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("VulnerabilityState"),
QStringLiteral("OriginatorChargeTypeId"),
QStringLiteral("FriendlyFire"),
QStringLiteral("OriginatorEquipmentNumber")});
break;
case EventType::BiteMessage:
break;
case EventType::WeaponAssignment:
case EventType::FireEvent:
attributeEventLookup.addAttributesToEvent(eventType, {
QStringLiteral("GearTypeId"),
QStringLiteral("ChargeTypeId")});
break;
case EventType::HitBuilding:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"),
QStringLiteral("ChargeTypeId"),
QStringLiteral("OriginatorEquipmentNumber"),
QStringLiteral("MainStructureElementId"),
QStringLiteral("VulnerabilityState"),
QStringLiteral("damagePercent"),
});
break;
case EventType::Manipulation:
break;
case EventType::Sanitation:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("Vitality"),
QStringLiteral("SanitationProceduresNeeded"),
QStringLiteral("SanitationProceduresTaken")});
break;
case EventType::CameraVideo:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"),
QStringLiteral("MainStructureElementId"),
QStringLiteral("duration"),
QStringLiteral("streamName")});
break;
case EventType::RadioCnr:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("PartyId"),
QStringLiteral("duration"),
QStringLiteral("streamName")});
break;
case EventType::RadioTvc:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("duration"),
QStringLiteral("streamName")});
break;
case EventType::HitEffectSimulation:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"),
QStringLiteral("AesName"),
QStringLiteral("OriginatorChargeTypeId")});
break;
case EventType::HitC:
case EventType::HitB:
case EventType::HitMine:
case EventType::EnterMineArea:
case EventType::LeaveMineArea:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
QStringLiteral("OriginatorChargeTypeId")});
break;
case EventType::HitN:
case EventType::HitGasPipe:
case EventType::EnterDangerArea:
case EventType::LeaveDangerArea:
case EventType::CrossLocalBorderline:
case EventType::CrossGlobalBorderline:
case EventType::EnterFunctionalArea:
case EventType::LeaveFunctionalArea:
case EventType::EnterNuclear:
case EventType::LeaveNuclear:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName")});
break;
case EventType::Borderline:
case EventType::NContamination:
case EventType::DangerArea:
case EventType::FunctionalArea:
case EventType::MineCorridor:
case ProjectDataManagement::EventType::GasPipe:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
QStringLiteral("duration")});
break;
case EventType::MineArea:
case EventType::BCContamination:
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesName"),
QStringLiteral("duration"),
QStringLiteral("ChargeTypeId")});
break;
case EventType::Unknown:
case EventType::FriendlyFire:
case EventType::TechnicalArea:
case EventType::EquipmentErrorReport:
case EventType::EmergencyCall:
Q_ASSERT(false);
continue;
}
addEventType(eventType);
}
addAttributeType(QStringLiteral("TimeRange"), tr("Time range:"), ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET , INTERPRETER_TYPE_TIME);
addAttributeType(QStringLiteral("VulnerabilityState"), tr("Vulnerability State:"));
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CombatReady);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::LightDamage);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MediumDamage);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HeavyDamage);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::MobilityKill);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleMobilityKill);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::WeaponSystemDamage);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::VisibleWeaponSystemDamage);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::CatastrophicKill);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::TemporarySeverance);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NearMiss);
addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::HitWithNoEffect);
addAttributeTypeWithYesAndNo(QStringLiteral("IsSituationType"), tr("Is situation type:"));
addAttributeTypeWithYesAndNo(QStringLiteral("IsVideoType"), tr("Is video type:"));
addAttributeTypeWithYesAndNo(QStringLiteral("IsAudioType"), tr("Is audio type:"));
addAttributeType(QStringLiteral("AesType"), tr("Aes Type:"));
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtNContamination);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBCContamination);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionArea);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionSingle);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineArea);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtDangerArea);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtFunctionalArea);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineCorridor);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtBorderline);
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineAreaSingleMines);
addAttributeTypeWithYesAndNo(QStringLiteral("FriendlyFire"), tr("Friendly Fire:"));
addAttributeTypeWithYesAndNo(QStringLiteral("DryFire"), tr("Dry Fire:"));
addAttributeType(QStringLiteral("MarkerName"), tr("Name:"), ATTRIBUTE_UI_TYPE_CHECKBOX , INTERPRETER_TYPE_NONE);
addAttributeType(QStringLiteral("MarkerNote"), tr("Note:"), ATTRIBUTE_UI_TYPE_CHECKBOX , INTERPRETER_TYPE_NONE);
addAttributeType(QStringLiteral("MarkerOffset"), tr("Offset [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET , INTERPRETER_TYPE_RANGE);
{
DetailData::AttributeParameterLookup::ParameterMap pm;
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(9999999));
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(QString()));
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
attributeParameterLookup.addParameter(QStringLiteral("MarkerOffset"), pm);
}
addAttributeType(QStringLiteral("duration"), tr("Duration [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET , INTERPRETER_TYPE_RANGE);
{
DetailData::AttributeParameterLookup::ParameterMap pm;
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(99999999));
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(QString()));
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
attributeParameterLookup.addParameter(QStringLiteral("duration"), pm);
}
addAttributeType(QStringLiteral("damagePercent"), tr("Damage [%]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET , INTERPRETER_TYPE_RANGE);
addRedirectedAttributeType(QStringLiteral("damagePercentOld"), tr("Damage before [%]:"), QStringLiteral("damagePercent"));
{
DetailData::AttributeParameterLookup::ParameterMap pm;
pm.insert(DetailData::UI_PARAM_TYPE_MIN, QVariant::fromValue<unsigned int>(0));
pm.insert(DetailData::UI_PARAM_TYPE_MAX, QVariant::fromValue<unsigned int>(100));
pm.insert(DetailData::UI_PARAM_TYPE_SUFFIX, QVariant::fromValue<QString>(tr(" %")));
pm.insert(DetailData::UI_PARAM_TYPE_PREFIX, QVariant::fromValue<QString>(QString()));
attributeParameterLookup.addParameter(QStringLiteral("damagePercent"), pm);
}
std::shared_ptr<ParticipantManagement::Interface::Dtc> dtcPpm;
m_session->getDtc<ParticipantManagement::DataInterface>(dtcPpm);
addAttributeType(QStringLiteral("EquipmentNumber"), tr("Equip. No.:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("EquipmentNumber"), new AvmEquipmentNumber(dtcPpm));
addRedirectedAttributeType(QStringLiteral("OriginatorEquipmentNumber"), tr("Equip. No. of Originator:"), QStringLiteral("EquipmentNumber"));
std::shared_ptr<ProjectDataManagement::Interface::Dtc> dtcPdm;
m_session->getDtc<ProjectDataManagement::DataInterface>(dtcPdm);
addAttributeType(QStringLiteral("ChargeTypeId"), tr("Charge Type:"));
addRedirectedAttributeType(QStringLiteral("OriginatorChargeTypeId"), tr("Originator Charge Type:"), QStringLiteral("ChargeTypeId"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("ChargeTypeId"), new AvmChargeType(dtcPdm));
addAttributeType(QStringLiteral("GearTypeId"), tr("Gear Type:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("GearTypeId"), new AvmGearType(dtcPdm));
addAttributeType(QStringLiteral("OriginatorType"), tr("Originator Type:"));
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Unknown);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Participant);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::AreaEffectSimulation);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ObserverController);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ExerciseControl);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::FunctionalArea);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Initialization);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::ImprovisedExplosiveDevice);
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::DusMine);
const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"),
QStringLiteral("HasPvSan"));
if (showPvSan)
addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::Sanitation);
std::shared_ptr<InfrastructureManagement::Interface::Dtc> dtcIsm;
m_session->getDtc<InfrastructureManagement::DataInterface>(dtcIsm);
addAttributeType(QStringLiteral("MainStructureElementId"), tr("Building:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("MainStructureElementId"), new AvmBuilding(dtcIsm));
addAttributeType(QStringLiteral("PartyId"), tr("Party:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("PartyId"), new AvmParty(dtcPpm));
std::shared_ptr<OperatorManagement::Interface::Dtc> dtcOpm;
m_session->getDtc<OperatorManagement::DataInterface>(dtcOpm);
addAttributeType(QStringLiteral("Operator"), tr("Operator:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("Operator"), new AvmOperator(dtcOpm));
std::shared_ptr<AudioVideoManagement::Interface::Dtc> dtcAvm;
m_session->getDtc<AudioVideoManagement::DataInterface>(dtcAvm);
addAttributeType(QStringLiteral("streamName"), tr("Stream Name:"));
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("streamName"), new AvmStreamName(dtcAvm));
}
DetailData::GetDetailDataResultList DetailData::getDetailData(const LtsTimelineClassic::Event *event)
{
GetDetailDataResultList result;
if (event->detailData().isEmpty())
return result;
const QJsonObject &root = event->detailData();
for (auto i = root.constBegin(); i != root.constEnd(); ++i)
{
DEBUG_LOG(m_logger) << "Adding Detail Data for: " << i.key();
result.append(getDetailDataForAttribute(i.key(), *i));
}
return result;
}
DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const LtsTimelineClassic::Event *event, const QString &attributeType)
{
GetDetailDataForAttributeResult result;
const QJsonObject &root = event->detailData();
root[QStringLiteral("TimeRange")] = event->startTime() / 1000 ;
root[QStringLiteral("PartyId")] = event->partyId();
const QJsonValue attribute = root[attributeType];
if (attribute.isNull() || attribute.isUndefined())
{
WARNING_LOG(m_logger) << "DetailData::getDetailDataForAttribute: no attribute type " << attributeType
<< " in " << QJsonDocument(root).toJson();
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
return result;
}
return getDetailDataForAttribute(attributeType, attribute);
}
DetailData::GetDetailDataForAttributeResult DetailData::getDetailDataForAttribute(const QString &attributeType, const QJsonValue &attributeValueJson)
{
GetDetailDataForAttributeResult result;
result.attributeTypeId = attributeType;
result.attributeValueId = -1;
result.requestResult = DetailData::RequestResult::Error;
QString attributeTypeTranslated = attributeTypeLookup.getAttributeText(attributeType);
if (attributeTypeTranslated.isEmpty())
{
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
return result;
}
result.attributeType = attributeTypeTranslated;
int attributeValueId = -1;
switch (attributeValueJson.type())
{
case QJsonValue::Double:
{
attributeValueId = attributeValueJson.toInt(-1);
break;
}
case QJsonValue::Null:
case QJsonValue::Undefined:
{
WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value is null or undefined! " << attributeValueJson.toString();
result.requestResult = DetailData::RequestResult::InvalidAttributeTypeJson;
return result;
}
case QJsonValue::Bool:
{
attributeValueId = attributeValueJson.toBool() ? 1 : 0;
break;
}
case QJsonValue::String:
{
bool k = false;
QString attributeValueString = attributeValueJson.toString();
if (attributeValueString.isEmpty())
{
attributeValueId = -1;
break;
}
attributeValueId = attributeValueString.toInt(&k);
if (!k)
{
result.attributeValue = attributeValueString;
result.requestResult = DetailData::RequestResult::Okay;
return result;
}
break;
}
default:
{
WARNING_LOG(m_logger) << "Timeline: DetailData::getDetailDataForAttribute: attribute value cannot be handled. Type " << attributeValueJson.type() << attributeValueJson.toString();
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
return result;
}
}
if (attributeValueId == -1)
{
result.requestResult = DetailData::RequestResult::InvalidAttributeType;
return result;
}
result.attributeValueId = attributeValueId;
int attributeUiType = attributeUITypeLookup.getUIType(attributeType);
switch (attributeUiType)
{
case ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET:
case ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET:
case ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET:
case ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET:
{
result.attributeValue = QString::number(attributeValueId);
result.requestResult = DetailData::RequestResult::Okay;
break;
}
case ATTRIBUTE_UI_TYPE_COMBO_BOX:
case ATTRIBUTE_UI_TYPE_CHECKBOX:
{
result.attributeValue = attributeValueLookup.getValueStringFromValueId(attributeType, attributeValueId);
if (result.attributeValue.isEmpty())
result.attributeValue = m_attributeValueLookupDtc.getValueStringFromValueId(attributeType, attributeValueId);
result.requestResult = DetailData::RequestResult::Okay;
break;
}
default:
{
QString concreteAttributeType = attributeRedirectionLookup.getRedirection(attributeType);
if (concreteAttributeType == attributeType)
{
ERROR_LOG(m_logger) << "getDetailDataForAttribute: attribute type " << attributeType << " does not have an UiType !!!";
result.requestResult = DetailData::RequestResult::NoUiTypeForAttribute;
}
else
{
QString attributeType = result.attributeType;
QString attributeTypeId = result.attributeTypeId;
result = getDetailDataForAttribute(concreteAttributeType, attributeValueJson);
result.attributeType = attributeType;
result.attributeTypeId = attributeTypeId;
}
break;
}
}
return result;
}
void DetailData::createRetrieveCurrentTimeCallback(LtsWidgets::LtsDateTimeEdit *dateTimeEdit)
{
dateTimeEdit->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
}
DetailData::LookupBase::LookupBase(const QString &lookupClassName)
: m_lookupClassName(lookupClassName)
, m_logger(getLogger(QStringLiteral("DetailData.") + lookupClassName))
{
}
DetailData::EventTypeLookup::EventTypeLookup()
: LookupBase(QStringLiteral("EventTypeLookup"))
{
}
void DetailData::EventTypeLookup::addEventType(const int key, const QString &value)
{
m_eventTypeMap.insert(key, value);
}
int DetailData::EventTypeLookup::getEventType(const QString &eventText) const
{
const QString paramText = removeSpaces(eventText);
for (auto i = m_eventTypeMap.constBegin(); i != m_eventTypeMap.constEnd(); ++i)
{
const QString mapText = removeSpaces(i.value());
if (mapText == paramText)
return i.key();
}
return -1;
}
QString DetailData::EventTypeLookup::getEventText(const int eventType) const
{
return m_eventTypeMap.value(eventType);
}
bool DetailData::EventTypeLookup::isEventExists(const int eventType) const
{
return m_eventTypeMap.contains(eventType);
}
QStringList DetailData::EventTypeLookup::getEventTexts() const
{
return m_eventTypeMap.values();
}
DetailData::AttributeEventLookup::AttributeEventLookup()
: LookupBase(QStringLiteral("AttributeEventLookup"))
{
}
void DetailData::AttributeEventLookup::addAttributesToEvent(const int eventType, const AttributeList &attributeTypeList)
{
AttributeList &al = m_attributeEventLookupMap[eventType];
al += attributeTypeList;
}
void DetailData::AttributeEventLookup::addAttributesToEvent(const ProjectDataManagement::EventType &eventType, const AttributeList &attributeTypeList)
{
addAttributesToEvent(eventType.underlying(), attributeTypeList);
}
bool DetailData::AttributeEventLookup::isAttributeInEvent(const int eventType, const QString &attributeType)
{
auto eventTypeIt = m_attributeEventLookupMap.constFind(eventType);
if (eventTypeIt == m_attributeEventLookupMap.constEnd())
return false;
const AttributeList &attributeList = *eventTypeIt;
if (attributeList.contains(attributeType))
return true;
return false;
}
DetailData::AttributeEventLookup::AttributeList DetailData::AttributeEventLookup::getEventsAttributeList(const int eventType) const
{
return m_attributeEventLookupMap.value(eventType);
}
DetailData::AttributeTypeLookup::AttributeTypeLookup()
: LookupBase(QStringLiteral("AttributeTypeLookup"))
{
}
void DetailData::AttributeTypeLookup::addAttributeText(const QString &attributeType, const QString &attributeText)
{
m_attributeTypeLookupMap.insert(attributeType, attributeText);
}
QString DetailData::AttributeTypeLookup::getAttributeType(const QString &attributeText) const
{
const QString paramText = removeSpaces(attributeText);
for (auto i = m_attributeTypeLookupMap.constBegin(); i != m_attributeTypeLookupMap.constEnd(); ++i)
{
const QString mapText = removeSpaces(i.value());
if (mapText == paramText)
return i.key();
}
WARNING_LOG(m_logger) << "getAttributeType: attribute type not found by text '" << attributeText << "'";
return QString();
}
DetailData::AttributeTypeLookup::AttributeTypeList DetailData::AttributeTypeLookup::getAttributeTypes() const
{
return m_attributeTypeLookupMap.keys();
}
QString DetailData::AttributeTypeLookup::getAttributeText(const QString &attributeType, const QString &defaultReturnValue) const
{
return m_attributeTypeLookupMap.value(attributeType, defaultReturnValue);
}
DetailData::AttributeTypeLookup::AttributeTextList DetailData::AttributeTypeLookup::getAttributeTexts() const
{
return m_attributeTypeLookupMap.values();
}
DetailData::AttributeParameterLookup::AttributeParameterLookup()
: LookupBase(QStringLiteral("AttributeParameterLookup"))
{
}
void DetailData::AttributeParameterLookup::addParameter(const QString &attributeType, const ParameterMap &parameterMap)
{
if (!parameterMap.count())
{
WARNING_LOG(m_logger) << "addParameter: parameter map is empty!";
return;
}
m_attributeParameterMap.insert(attributeType, parameterMap);
}
DetailData::AttributeParameterLookup::ParameterMap DetailData::AttributeParameterLookup::getParameterMap(const QString &attributeType) const
{
return m_attributeParameterMap.value(attributeType);
}
QVariant DetailData::AttributeParameterLookup::getParameterValue(const QString &attributeType, const int parameterType) const
{
const ParameterMap &pm = getParameterMap(attributeType);
auto pmci = pm.constFind(parameterType);
if (pmci == pm.constEnd())
return QVariant();
return *pmci;
}
DetailData::AttributeUITypeLookup::AttributeUITypeLookup()
: LookupBase(QStringLiteral("AttributeUITypeLookup"))
{
}
void DetailData::AttributeUITypeLookup::addUITypeToAttribute(const QString &attributeType, const int uiType)
{
m_attributeUITypeLookupMap.insert(attributeType, uiType);
}
int DetailData::AttributeUITypeLookup::getUIType(const QString &attributeType) const
{
return m_attributeUITypeLookupMap.value(attributeType, -1);
}
DetailData::AttributeInterpreterLookup::AttributeInterpreterLookup()
: LookupBase(QStringLiteral("AttributeInterpreterLookup"))
{
}
void DetailData::AttributeInterpreterLookup::addInterpreterTypeToAttribute(const QString &attributeType, const int interpreterType)
{
m_attributeInterpreterLookupMap.insert(attributeType, interpreterType);
}
int DetailData::AttributeInterpreterLookup::getInterpreterType(const QString &attributeType) const
{
return m_attributeInterpreterLookupMap.value(attributeType);
}
DetailData::AttributeValueLookup::AttributeValueLookup()
: LookupBase(QStringLiteral("AttributeValueLookup"))
{
}
void DetailData::AttributeValueLookup::removeValueFromAttributeValueMap(const QString &attributeType, const int valueKey)
{
auto attributeTypeValueMapIt = m_attributeTypeValueMap.find(attributeType);
if (attributeTypeValueMapIt == m_attributeTypeValueMap.end())
return;
AttributeValueMap &currentAttributeValueMap = *attributeTypeValueMapIt;
currentAttributeValueMap.remove(valueKey);
}
void DetailData::AttributeValueLookup::addValueToAttributeValueMap(const QString &attributeType, const int valueKey, const QString &valueValue)
{
AttributeValueMap &avm = m_attributeTypeValueMap[attributeType];
avm.insert(valueKey, valueValue);
}
void DetailData::AttributeValueLookup::addValuesToAttributeValueMap(const QString &attributeType, const AttributeValueMap &avm)
{
AttributeValueMap &thisAvm = m_attributeTypeValueMap[attributeType];
for (auto i = avm.constBegin(); i != avm.constEnd(); ++i)
{
thisAvm.insert(i.key(), i.value());
}
}
AttributeValueMap DetailData::AttributeValueLookup::getAttributeValueMap(const QString &attributeType) const
{
return m_attributeTypeValueMap.value(attributeType);
}
QString DetailData::AttributeValueLookup::getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString& defaultValue) const
{
return getAttributeValueMap(attributeType).value(attributeValueId, defaultValue);
}
void DetailData::AttributeValueLookup::clear()
{
m_attributeTypeValueMap.clear();
}
DetailData::AttributeRedirectionLookup::AttributeRedirectionLookup()
: LookupBase(QStringLiteral("AttributeRedirectionLookup"))
{
}
void DetailData::AttributeRedirectionLookup::addRedirection(const QString &attributeType, const QString &redirectTo)
{
m_attributeRedirectionMap.insert(attributeType, redirectTo);
}
QString DetailData::AttributeRedirectionLookup::getRedirection(const QString &attributeType) const
{
auto it = m_attributeRedirectionMap.find(attributeType);
if (it == m_attributeRedirectionMap.end())
return attributeType;
return it.value();
}
}
@@ -0,0 +1,332 @@
#pragma once
#include "logger.h"
#include <LtsUtilsCore/data_modification_enum.h>
#include <LtsSession/lts_session.h>
#include <Services/ProjectDataManagement/pdm_enums.hpp>
#include <QHash>
#include <QMap>
#include <QObject>
#include "attribute_value_lookup.h"
namespace LtsSession
{
class LtsSession;
}
namespace LtsTimelineClassic
{
class Event;
}
namespace LtsWidgets
{
class LtsDateTimeEdit;
}
namespace Timeline
{
constexpr int markerTypeId = 999999;
class DetailData : public QObject
{
Q_OBJECT
public:
enum class RequestResult
{
Error = 0,
Okay = 1,
InvalidAttributeType,
NoValueTranslationForAttribute,
NoUiTypeForAttribute,
InvalidAttributeTypeJson,
JsonCorrupted
};
struct GetDetailDataForAttributeResult
{
QString attributeType;
QString attributeValue;
QString attributeTypeId;
int attributeValueId = 0;
RequestResult requestResult = RequestResult::Error;
};
using GetDetailDataResultList = QVector<GetDetailDataForAttributeResult>;
enum AttributeUITypes
{
ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET = 0,
ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET,
ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET,
ATTRIBUTE_UI_TYPE_COMBO_BOX,
ATTRIBUTE_UI_TYPE_CHECKBOX,
ATTRIBUTE_UI_TYPE_RAD_RANGE_WIDGET
};
enum UIParameterType
{
UI_PARAM_TYPE_N1,
UI_PARAM_TYPE_N2,
UI_PARAM_TYPE_O1,
UI_PARAM_TYPE_O2,
UI_PARAM_TYPE_RAD,
UI_PARAM_TYPE_MIN,
UI_PARAM_TYPE_MAX,
UI_PARAM_TYPE_PREFIX,
UI_PARAM_TYPE_SUFFIX
};
enum InterpreterTypes
{
INTERPRETER_TYPE_NONE = 0,
INTERPRETER_TYPE_RANGE,
INTERPRETER_TYPE_AREA,
INTERPRETER_TYPE_ID_COMPARE,
INTERPRETER_TYPE_STR_COMPARE,
INTERPRETER_TYPE_POSITION,
INTERPRETER_TYPE_TIME,
INTERPRETER_TYPE_DURATION,
INTERPRETER_TYPE_RAD
};
explicit DetailData(LtsSession::LtsSession *session, QObject *parent = nullptr);
void populate();
GetDetailDataResultList getDetailData(const LtsTimelineClassic::Event *event);
GetDetailDataForAttributeResult getDetailDataForAttribute(const LtsTimelineClassic::Event *event, const QString &attributeType);
void createRetrieveCurrentTimeCallback(LtsWidgets::LtsDateTimeEdit *dateTimeEdit);
LtsSession::LtsSession *session() { return m_session; }
private:
void addRedirectedAttributeType(const QString &newAttributeTypeId, const QString &attributeText, const QString &redirectToAttributeTypeId);
void addAttributeType(const QString &attributeTypeId, const QString &attributeText, const int uiTypeId = ATTRIBUTE_UI_TYPE_COMBO_BOX, const int interpreterTypeId = INTERPRETER_TYPE_ID_COMPARE);
void addAttributeTypeWithYesAndNo(const QString &attributeTypeId, const QString &attributeText)
{
addAttributeType(attributeTypeId, attributeText, ATTRIBUTE_UI_TYPE_CHECKBOX);
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, 0, tr("No"));
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, 1, tr("Yes"));
}
template <typename AttributeEnumType>
void addAttributeValue(const QString &attributeTypeId, const AttributeEnumType &attributeEnum)
{
attributeValueLookup.addValueToAttributeValueMap(attributeTypeId, (int)attributeEnum, toString(attributeEnum));
}
void addEventType(int eventTypeId, const QString &eventTypeString);
void addEventType(const ProjectDataManagement::EventType &eventType);
GetDetailDataForAttributeResult getDetailDataForAttribute(const QString &attributeType, const QJsonValue &attributeValueJson);
LtsSession::LtsSession *m_session;
bool __already_populated__;
NGL::INGLLogger &m_logger;
public:
class LookupBase
{
public:
explicit LookupBase(const QString &lookupClassName);
protected:
QString m_lookupClassName;
NGL::INGLLogger &m_logger;
};
class EventTypeLookup : public LookupBase
{
public:
using EventTypeMap = QMap<int , QString >;
EventTypeLookup();
void addEventType(const int key, const QString &value);
int getEventType(const QString &eventText) const;
QString getEventText(const int eventType) const;
QStringList getEventTexts() const;
bool isEventExists(const int eventType) const;
private:
EventTypeMap m_eventTypeMap;
};
EventTypeLookup eventTypeLookup;
class AttributeTypeLookup : public LookupBase
{
public:
using AttributeTypeLookupMap = QMap<QString , QString >;
using AttributeTypeList = QList<QString>;
using AttributeTextList = QStringList;
AttributeTypeLookup();
void addAttributeText(const QString &attributeType, const QString &attributeText);
QString getAttributeType(const QString &attributeText) const;
AttributeTypeList getAttributeTypes() const;
QString getAttributeText(const QString &attributeType, const QString &defaultReturnValue = QString()) const;
AttributeTextList getAttributeTexts() const;
private:
AttributeTypeLookupMap m_attributeTypeLookupMap;
};
AttributeTypeLookup attributeTypeLookup;
class AttributeEventLookup : public LookupBase
{
public:
using AttributeEventLookupMap = QMap<int , QList<QString> >;
using AttributeList = QList<QString>;
AttributeEventLookup();
void addAttributesToEvent(const int eventType, const AttributeList &attributeTypeList);
void addAttributesToEvent(const ProjectDataManagement::EventType &eventType, const AttributeList &attributeTypeList);
bool isAttributeInEvent(const int eventType, const QString &attributeType);
AttributeList getEventsAttributeList(const int eventType) const;
private:
AttributeEventLookupMap m_attributeEventLookupMap;
};
AttributeEventLookup attributeEventLookup;
class AttributeParameterLookup : public LookupBase
{
public:
using ParameterMap = QMap<int, QVariant>;
using AttributeParameterMap = QHash<QString, ParameterMap>;
AttributeParameterLookup();
void addParameter(const QString &attributeType, const ParameterMap &parameterMap);
ParameterMap getParameterMap(const QString &attributeType) const;
QVariant getParameterValue(const QString &attributeType, const int parameterType) const;
private:
AttributeParameterMap m_attributeParameterMap;
};
AttributeParameterLookup attributeParameterLookup;
class AttributeUITypeLookup : public LookupBase
{
public:
using AttributeUITypeLookupMap = QHash<QString, int>;
AttributeUITypeLookup();
void addUITypeToAttribute(const QString &attributeType, const int uiType);
int getUIType(const QString &attributeType) const;
private:
AttributeUITypeLookupMap m_attributeUITypeLookupMap;
};
AttributeUITypeLookup attributeUITypeLookup;
class AttributeInterpreterLookup : public LookupBase
{
public:
using AttributeInterpreterLookupMap = QHash<QString, int>;
AttributeInterpreterLookup();
void addInterpreterTypeToAttribute(const QString &attributeType, const int interpreterType);
int getInterpreterType(const QString &attributeType) const;
private:
AttributeInterpreterLookupMap m_attributeInterpreterLookupMap;
};
AttributeInterpreterLookup attributeInterpreterLookup;
class AttributeValueLookup : public LookupBase
{
public:
AttributeValueLookup();
void addValueToAttributeValueMap(const QString &attributeType, const int valueKey, const QString &valueValue );
void removeValueFromAttributeValueMap(const QString &attributeType, const int valueKey);
void addValuesToAttributeValueMap(const QString &attributeType, const AttributeValueMap &avm);
void clear();
AttributeValueMap getAttributeValueMap(const QString &attributeType) const;
QString getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString &defaultValue = QString()) const;
private:
AtributeValueLookupMap m_attributeTypeValueMap;
};
AttributeValueLookup attributeValueLookup;
class AttributeValueLookupDtc : public LookupBase
{
public:
AttributeValueLookupDtc() : LookupBase(QStringLiteral("AttributeValueLookupDtc")) {}
~AttributeValueLookupDtc() { qDeleteAll(m_provider); }
void addHandlerForDtc(const QString &attributeType, AttributeValueLookupProvider *provider)
{
auto &p = m_provider[attributeType];
delete p;
p = provider;
}
AttributeValueMap getAttributeValueMap(int eventType, const QString &attributeType) const
{
const auto provider = m_provider.value(attributeType);
if (!provider)
return {};
return provider->getAttributeValueMap(eventType);
}
QString getValueStringFromValueId(const QString &attributeType, int attributeValueId) const
{
const auto provider = m_provider.value(attributeType);
if (!provider)
return {};
return provider->getValueStringFromValueId(attributeValueId);
}
private:
QHash<QString, AttributeValueLookupProvider*> m_provider;
};
AttributeValueLookupDtc m_attributeValueLookupDtc;
AttributeValueMap operatorsForEventType(int eventType) const;
QString operatorNameFromId(int id) const;
class AttributeRedirectionLookup : public LookupBase
{
public:
using AttributeRedirectionMap = QHash<QString, QString>;
explicit AttributeRedirectionLookup();
void addRedirection(const QString &attributeType, const QString &redirectTo);
QString getRedirection(const QString &attributeType) const;
private:
AttributeRedirectionMap m_attributeRedirectionMap;
};
AttributeRedirectionLookup attributeRedirectionLookup;
};
}
@@ -0,0 +1,200 @@
#include "excon_filter.h"
#include "detail_data.h"
#include "EventFilter/interpreter/FilterWorker.h"
#include "EventFilter/interpreter/FilterEquationFunctions.h"
#include <LtsTimelineClassic/EventList.h>
#include <LtsTimelineClassic/Event.h>
#include <ProjectDataManagement/pdm_enums.hpp>
#include "logger.h"
#include <QVariant>
namespace Timeline
{
static LtsTimelineClassic::EventList applyFilter(DetailData *detailData,
const LtsTimelineClassic::EventList &eventList,
const ModelFilterList &modelFilterList,
bool simulation)
{
NGL::INGLLogger &logger(getLogger("ExconFilter"));
LtsTimelineClassic::EventList visibleEvents;
bool resetFilterOnly = false;
if (!modelFilterList.count())
{
DEBUG_LOG(logger) << "applyFilter: Model Filter List is EMPTY";
if (simulation)
return visibleEvents;
resetFilterOnly = true;
}
visibleEvents = eventList;
QSet<int> mentionedEventTypes;
mentionedEventTypes.insert(markerTypeId);
for (const FilterWorker::ModelFilter &mf : modelFilterList)
{
if (mf.active)
mentionedEventTypes.insert(mf.eventType);
}
bool showAllEvents = false;
if (mentionedEventTypes.count() == 1 && mentionedEventTypes.contains(0 ))
showAllEvents = true;
for (LtsTimelineClassic::Event *event : eventList)
{
if (!event)
{
WARNING_LOG(logger) << "applyFilter: Erroneous event!";
continue;
}
int eventType = event->typeId();
if (resetFilterOnly )
{
if (!simulation)
event->show();
continue;
}
bool eventVisible = true;
if (!showAllEvents && !mentionedEventTypes.contains(eventType))
eventVisible = false;
if (!eventVisible )
{
if (!simulation)
event->hide();
visibleEvents.removeAll(event);
continue;
}
const auto eventsAttributeList = detailData->attributeEventLookup.getEventsAttributeList(eventType);
for (const QString &attributeType : eventsAttributeList)
{
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
bool visibleByAttribute = false;
bool attributeTypeMentioned = false;
for (const FilterWorker::ModelFilter &mf : modelFilterList)
{
if (mf.eventType == eventType || mf.eventType == 0 )
{
if (mf.attributeType == concreteAttributeType && mf.active)
{
attributeTypeMentioned = true;
DetailData::GetDetailDataForAttributeResult result = detailData->getDetailDataForAttribute(event, attributeType);
if (result.requestResult != DetailData::RequestResult::Okay)
result = detailData->getDetailDataForAttribute(event, concreteAttributeType);
if (result.requestResult != DetailData::RequestResult::Okay)
{
WARNING_LOG(logger) << "applyFilter: result.requestResult != DetailData::OKAY -" << (int)result.requestResult;
continue;
}
visibleByAttribute = FilterEquationFunctions::checkValue(detailData, concreteAttributeType, result.attributeValueId, mf.attributeValue);
if (visibleByAttribute)
break;
#ifdef DEBUG
DEBUG_LOG(logger)
<< "\r\napplyFilter:\r\n"
<< "Evnt Type (" << eventType << ")\r\n"
<< "Attr Type (" << attributeType << ")\r\n"
<< "Evnt Val (" << result.resultValue << ")\r\n"
<< "Fltr Val (" << mf.attributeValue << ")\r\n"
<< "Evnt SHOW (" << eventVisible << ")\r\n"
<< "Attr SHOW (" << visibleByAttribute << ")\r\n";
#endif
}
}
}
if (attributeTypeMentioned && !visibleByAttribute)
{
eventVisible = false;
break;
}
}
if (!simulation)
event->setVisible(eventVisible);
if (!eventVisible)
visibleEvents.removeAll(event);
}
DEBUG_LOG(logger) << "applyFilter: Visible Events after applying filter:" << visibleEvents.count();
return visibleEvents;
}
LtsTimelineClassic::EventList setFilter(DetailData *detailData,
const LtsTimelineClassic::EventList &eventListToFilter,
const QJsonArray &filter,
QWidget *parentWidget,
bool simulation,
bool handleResult)
{
LtsTimelineClassic::EventList visibleEvents;
FilterWorker::GetModelFilterListResult result = FilterWorker::getModelFilterList(detailData, filter, true );
ModelFilterList modelFilterList = result.result;
if (handleResult)
FilterWorker::getInstance()->handleResultValues(result.resultValueList, parentWidget);
visibleEvents = applyFilter(detailData, eventListToFilter, modelFilterList, simulation);
return visibleEvents;
}
}
@@ -0,0 +1,22 @@
#pragma once
#include <LtsTimelineClassic/EventList.h>
#include <QJsonArray>
class QWidget;
namespace Timeline
{
class DetailData;
LtsTimelineClassic::EventList setFilter(DetailData *detailData,
const LtsTimelineClassic::EventList &eventListToFilter,
const QJsonArray &filter,
QWidget *parentWidget,
bool simulation = false,
bool handleResult = true);
}
@@ -0,0 +1,32 @@
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace Timeline
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "Plugins.Timeline.Gui.";
std::string loggerName;
const size_t len = strlen(name);
loggerName.reserve(sizeof(ns) + len);
loggerName.append(ns, sizeof(ns) - 1);
loggerName.append(name, len);
try
{
return NGL::NGLLoggerBootstrap::getNGLRootLogger().
getNGLLogger(loggerName);
}
catch (const std::exception &ex)
{
fprintf(stderr, "Error retrieving logger: %s", ex.what());
abort();
}
}
}
@@ -0,0 +1,17 @@
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace Timeline
{
using LOGGER_T = NGL::INGLLogger &;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
}
@@ -0,0 +1,104 @@
#include "tln_cache_dialog.h"
#include "ui_tln_cache_dialog.h"
#include <QDateTime>
#include <QDebug>
namespace Timeline
{
TimelineCacheDialog::TimelineCacheDialog(QWidget *parent)
: QDialog(parent)
, m_ui(new Ui::TimelineCacheDialog)
{
m_ui->setupUi(this);
connect(m_ui->pbUncache, &QPushButton::clicked,
this, [this]()
{
bool k = false;
int index = m_ui->twCaches->item(m_ui->twCaches->selectionModel()->currentIndex().row(), 0)->text().toInt(&k);
if (!k)
return;
emit signalUncache(index);
close();
});
connect(m_ui->pbDelete, &QPushButton::clicked,
this, [this]()
{
bool k = false;
int index = m_ui->twCaches->item(m_ui->twCaches->selectionModel()->currentIndex().row(), 0)->text().toInt(&k);
if (!k)
return;
emit signalDelete(index);
close();
});
}
TimelineCacheDialog::~TimelineCacheDialog()
{
delete m_ui;
}
void TimelineCacheDialog::addCache(const CacheRange &cr, const QString &indexString)
{
int rowCount = m_ui->twCaches->rowCount();
m_ui->twCaches->insertRow(rowCount);
int row = m_ui->twCaches->rowCount() - 1;
int c = 0;
m_ui->twCaches->setItem(row, c++ , new QTableWidgetItem(indexString));
QString hash(QStringLiteral("<%1:%2:%3>").arg(cr.start).arg(cr.end).arg(cr.events.count()));
m_ui->twCaches->setItem(row, c++, new QTableWidgetItem(QString::number(qHash(hash), 16)));
m_ui->twCaches->setItem(row, c++, new QTableWidgetItem(QStringLiteral("%1 (%2)").arg(QDateTime::fromMSecsSinceEpoch(cr.start).toString()).arg(cr.start)));
m_ui->twCaches->setItem(row, c++, new QTableWidgetItem(QStringLiteral("%1 (%2)").arg(QDateTime::fromMSecsSinceEpoch(cr.end).toString()).arg(cr.end)));
m_ui->twCaches->setItem(row, c++, new QTableWidgetItem(QString::number(cr.events.count())));
}
bool TimelineCacheDialog::init(const QVector<QPair<qint64, CacheRange>> &cachedRanges, const CacheRange &liveCache)
{
m_ui->twCaches->setRowCount(0);
int eventCount = 0;
{
int i = 0;
for (auto it = cachedRanges.constBegin(); it != cachedRanges.constEnd(); ++it)
{
const CacheRange &cr = it->second;
eventCount += cr.events.count();
addCache(cr, QString::number(i));
i++;
}
}
addCache(liveCache, QStringLiteral("live"));
m_ui->lblEventCount->setText(QString::number(eventCount));
for (int i = 0; i < m_ui->twCaches->columnCount(); i++)
{
m_ui->twCaches->resizeColumnToContents(i);
}
return true;
}
}
@@ -0,0 +1,41 @@
#pragma once
#include "tln_dialog_model.h"
#include <QDialog>
#include <QVector>
namespace Ui
{
class TimelineCacheDialog;
}
namespace Timeline
{
class TimelineCacheDialog : public QDialog
{
Q_OBJECT
public:
explicit TimelineCacheDialog(QWidget *parent = nullptr);
~TimelineCacheDialog();
bool init(const QVector<QPair<qint64, CacheRange> > &cachedRanges, const CacheRange &liveCache);
private:
void addCache(const CacheRange &cache, const QString &indexString);
Ui::TimelineCacheDialog *m_ui;
signals:
void signalUncache(int index);
void signalDelete(int index);
};
}
@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TimelineCacheDialog</class>
<widget class="QWidget" name="TimelineCacheDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>846</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Cache View</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Event count:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblEventCount">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Never uncache events from a stale cache vector !</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="twCaches">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>100</number>
</attribute>
<column>
<property name="text">
<string>idx</string>
</property>
</column>
<column>
<property name="text">
<string>hash</string>
</property>
</column>
<column>
<property name="text">
<string>start</string>
</property>
</column>
<column>
<property name="text">
<string>end</string>
</property>
</column>
<column>
<property name="text">
<string>event count</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pbUncache">
<property name="text">
<string>uncache selected</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbDelete">
<property name="text">
<string>delete selected</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,167 @@
#pragma once
#include "tln_view_gui_plugin.h"
#include <LtsWidgets/lts_dialog.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include <LtsTimelineClassic/EventList.h>
#include <Plugins/Timeline/tln_data_plugin_interface.h>
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
#include <Plugins/SituationReplayManagement/srm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
#include <Plugins/FilterManagement/flt_participant_plugin_interface.h>
#include <Plugins/FilterManagement/flt_building_cmpnt_plugin_interface.h>
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
#include <QJsonArray>
namespace AudioVideoManagement
{
class StreamNameMapping;
}
namespace LtsTimelineClassic
{
class EventGraphic;
class Event;
}
namespace Ui
{
class TimelineViewDialog;
}
namespace LtsSession
{
class LtsSession;
}
namespace LtsPluginManager
{
class LtsPluginManager;
}
namespace Timeline
{
class FilterWindow;
class DetailData;
class DDSTimelineModel;
class EventListDialog;
class TimelineLegendDialog;
class TimelineViewDialog : public LtsWidgets::LtsDialog
, protected SituationReplayManagement::Interface::Ftc::ReplayPartitionCreateReplyHandler
{
Q_OBJECT
public:
explicit TimelineViewDialog(const QString &menuGroup, const LtsWidgets::ButtonCombination &buttonCombo, bool isMain, QWidget *parent = nullptr);
~TimelineViewDialog();
bool 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);
private slots:
void showDetailsAction(LtsTimelineClassic::EventGraphic *eg, int action);
void showDetails(const LtsTimelineClassic::EventList &eventList);
void slotApplyFilter(const QJsonArray &filter);
void slotShowEventDetails(const LtsTimelineClassic::Event *event);
void slotShowEvents(const QJsonArray &filter);
void slotWaitForReady();
void slotShowFiltersDialog();
void slotShowLegend();
void slotStartReplaySituation();
void updateRange(bool initial = false);
void slotLoading();
void slotLoadingDone();
void slotSpanChanged();
void slotEventTypesChanged(QSet<int> activeEventTypeIds);
void loadAllEvents();
void slotDebugCreateFakeEvent();
signals:
void signalWaitForReady();
void signalInitEventList();
private:
void retranslate() override;
void onReplayPartitionCreateReply(const Core::FunctionReplyObject &reply) override { m_requestHelper->requestReply(reply); }
qint64 currentSpanTime() const;
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
std::shared_ptr<MarkerManagement::Interface::Dtc> m_mrkDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> m_ppmInfoIfc;
std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> m_avmIfc;
std::shared_ptr<MarkerManagement::ForeignGuiInterface> m_mrkIfc;
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srmDataIfc;
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> m_fltParticipantIfc;
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> m_fltAesIfc;
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> m_fltBuildingComponentIfc;
Ui::TimelineViewDialog *m_ui;
QString m_menuGroup;
DDSTimelineModel *m_model;
DetailData *m_detailData;
FilterWindow *m_filterWindow;
QPointer<EventListDialog> m_eventListDialog;
QPointer<EventListDialog> m_allEventsListDialog;
LtsSession::LtsSession *m_session;
LtsUtils::RequestHelper *m_requestHelper;
QPointer<LtsPluginManager::LtsPluginManager> m_replayApp;
QPointer<LtsSession::LtsSession> m_replayAppSession;
AudioVideoManagement::StreamNameMapping *m_streamNameMapping;
bool m_rangeChanged;
QJsonArray m_filter;
int m_loadingCount;
bool m_armed;
qint64 m_exerciseStart;
TimelineLegendDialog *m_legendDialog;
QTimer *m_armTimer;
NGL::INGLLogger &m_logger;
void setCustomSpan();
void calculateAndSetRange();
void setRange(qint64 min, qint64 max);
void updateActiveEventTypesByFilters();
void updateFiltersByActiveEventTypes();
void applyFilter(const QJsonArray &filter, bool doUpdateActiveEventTypes = true, bool reloadFilterWindow = false);
void rangeChanged();
void setTimelineUsable(bool usable = true);
void aboutToClose() override;
};
}
@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TimelineViewDialog</class>
<widget class="QWidget" name="TimelineViewDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1401</width>
<height>519</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Timeline View</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Time span:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbLive">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Live</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblStartTime">
<property name="text">
<string>Start:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbStartTime">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollBar" name="sbSpan">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="singleStep">
<number>3600</number>
</property>
<property name="pageStep">
<number>3600</number>
</property>
<property name="tracking">
<bool>true</bool>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblEndTime">
<property name="text">
<string>End:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbEndTime">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblNoEventsSelected">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#ff5656;&quot;&gt;Please create at least one filter of any event type to see events.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="LtsTimelineClassic::TimelineWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="debugWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>-</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string notr="true">Cursor at </string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblCursorTime">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cbFake">
<property name="text">
<string notr="true">[fake]</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbUpdate">
<property name="text">
<string notr="true">[update]</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbShowCache">
<property name="text">
<string notr="true">[show cache]</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbDebugCreateFakeEvent">
<property name="text">
<string notr="true">[create fake event]</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsTimelineClassic::TimelineWidget</class>
<extends>QWidget</extends>
<header location="global">LtsTimelineClassic/TimelineWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,203 @@
#pragma once
#include "detail_data.h"
#include <LtsTimelineClassic/AbstractTimelineModel.h>
#include <Plugins/Timeline/tln_data_plugin_interface.h>
#include <Plugins/MarkerManagement/mrk_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <QJsonArray>
#include <QAbstractSocket>
namespace LtsUtils
{
class RequestHelper;
}
namespace LtsSession
{
class LtsSession;
}
namespace AudioVideoManagement
{
class StreamNameMapping;
}
namespace Timeline
{
struct CacheRange : public LtsTimelineClassic::Range
{
QVector<LtsTimelineClassic::Event *> events;
bool incomplete = true;
bool visible = false;
};
class DDSTimelineModel : public LtsTimelineClassic::AbstractTimelineModel
{
Q_OBJECT
public:
explicit DDSTimelineModel(QObject *parent);
~DDSTimelineModel();
bool 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<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
LtsSession::LtsSession *session,
Timeline::DetailData *detailData,
AudioVideoManagement::StreamNameMapping *streamNameMapping);
void applyFilter(const QJsonArray &filter);
void setDetailData(DetailData *detailData) { m_detailData = detailData; }
void setColorPaintFun(LtsTimelineClassic::Event::EventPaintFunc &paintFunc, QColor &color, ProjectDataManagement::EventType eventType) const;
void setTimeRange(qint64 min, qint64 max);
void getEvents(qint64 rangeMin, qint64 rangeMax);
QVector<LtsTimelineClassic::Range> getKnownRanges() const;
const QVector<QPair<qint64, CacheRange>> &cachedEvents() const { return m_cachedEvents; }
const CacheRange &liveCache() const { return m_liveCache; }
void forceUncache();
void setLive(bool isLive = true);
void setCreateFakeEvents(bool createFakeEvents = true);
void setActiveEventTypeIds(const QSet<int> &activeEventTypeIds);
const QSet<int> &activeEventTypeIds() const { return m_activeEventTypeIds; }
bool hasActiveEventTypes() const { return !m_activeEventTypeIds.isEmpty(); }
void getAllEventsOfType(const QSet<int> &eventTypeIds);
private:
qint64 currentTime() const override;
QStringList getPathForAvsEvents(const QString &type, const QJsonObject &obj) const;
QStringList getPathForBuildingEvents(const QString &type, const QJsonObject &obj) const;
QStringList getPathForAesEvents(const QString &type, const QJsonObject &obj) const;
void addMarkerManagementMarker(const MarkerManagement::Marker &data);
void addEventsAndFilter(const QVector<LtsTimelineClassic::Event *> &eventList);
void addEventAndFilter(LtsTimelineClassic::Event *event);
void deleteMarker(int uniqueId);
void modifyMarker(const MarkerManagement::Marker &data);
QJsonObject createMarkerDetailData(const MarkerManagement::Marker &data) const;
LtsTimelineClassic::Event *getMarker(int uniqueId);
void checkCache();
void removeEvent(int eventId);
void addCacheRange(const LtsTimelineClassic::Range &range, const QVector<LtsTimelineClassic::Event *> &cachedEvents, qint64 incompleteEnd, bool addToTimeline = true);
bool isLive() const { return m_isLive; }
LtsTimelineClassic::Event *createEvent(const ExerciseEventManagement::Event &data) const;
bool checkDetailData(const LtsTimelineClassic::Event *event) const;
void processEventList(qint64 &highest, bool &incomplete, QVector<LtsTimelineClassic::Event *> &cachedEvents, QVector<LtsTimelineClassic::Event *> &eventList, const int initialCount = 0);
void receivedEvents(const LtsTimelineClassic::Range &range, QVector<LtsTimelineClassic::Event *> &receivedEventsList);
void requestEvents(const LtsTimelineClassic::Range &range);
QVector<LtsTimelineClassic::Event *> createTestEvents(qint64 time, int count, qint64 distance, qint64 duration = 0);
static bool isInsideCachedRange(const CacheRange &cacheRange, qint64 start, qint64 end);
bool isCached(int eventId) const;
void showCached(CacheRange &cacheRange);
bool isCacheFull() const;
void uncache(CacheRange &cr);
const CacheRange *getCache(int eventId) const;
void addCacheRangeToTimeline(const CacheRange &cr);
bool splitLowest(qint64 &rangeMin, qint64 rangeMax, qint64 &requestMin, qint64 &requestMax, const CacheRange &lowestCache) const;
void rebuildTimelineKnownRanges();
void _uncache(const CacheRange &cr);
void saveAndClearLiveCache();
const QJsonObject getDetailData(const ExerciseEventManagement::Event &event) const;
const QJsonObject getDetailData(const QByteArray &data, int id, const ProjectDataManagement::EventType& type, qint64 startTime) const;
std::shared_ptr<TimeLineManagement::ForeignDataInterface> m_eemForeign;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_dtcExm;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<MarkerManagement::Interface::Dtc> m_mrkDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
QJsonArray m_filter;
LtsSession::LtsSession *m_session;
int64_t m_startTime;
int64_t m_endTime;
DetailData *m_detailData;
AudioVideoManagement::StreamNameMapping *m_streamNameMapping;
bool m_isLive;
int m_cacheSize;
int m_maxCacheRanges;
int m_eventCount;
qint64 m_lastCachedEventsId;
QVector<QPair<qint64, CacheRange>> m_cachedEvents;
CacheRange m_liveCache;
bool m_createFakeEvents;
QSet<int> m_activeEventTypeIds;
QVector<int> m_knownMarkerIds;
NGL::INGLLogger &m_logger;
public slots:
void slotAddLiveEvent(const ExerciseEventManagement::Event &event);
private slots:
void slotMarkerChanged(const MarkerManagement::Marker &data, DataModification modType);
void slotAddLiveEventsFake();
void slotRequestMessageReceived(const QString &message);
signals:
void signalTooMuchEvents();
void signalRebuildTimelineKnownRanges();
void signalLoading();
void signalLoadingDone();
};
class EventRequest : public QObject
{
Q_OBJECT
public:
EventRequest(const QUrl &url, qint64 start, qint64 end, const QSet<int> &eventTypes, int limit);
~EventRequest() = default;
void append(LtsTimelineClassic::Event *newEvent) { m_eventList.push_back(newEvent); }
const QVector<LtsTimelineClassic::Event *> &eventList() const { return m_eventList; }
qint64 start() const { return m_start; }
qint64 end() const { return m_end; }
private:
void requestFailed(const QString &errorString);
qint64 m_start;
qint64 m_end;
QVector<LtsTimelineClassic::Event *> m_eventList;
QTimer *m_timeoutTimer;
private slots:
void slotRequestFailed();
void slotMessageReceived(const QString &message);
signals:
void signalRequestFailed(const QString &errorString);
void signalMessageReceived(const QString &message);
void signalDone();
void signalTimeout();
};
}
@@ -0,0 +1,274 @@
#include "tln_event_list.h"
#include "tln_event_list_columns.h"
#include "ui_tln_event_list.h"
#include "ui_tln_event_list_columns.h"
#include "tln_event_list_model.h"
#include "tln_show_details.h"
#include <Viewer/LtsDataView/lts_data_view.h>
#include <LtsTimelineClassic/EventGraphic.h>
#include <LtsPrinting/printing.h>
#include <QHeaderView>
#include <QTreeView>
const int MAX_EVENTS = 30;
namespace Timeline
{
EventListDialog::EventListDialog(const QString &menuGroup,
LtsSession::LtsSession *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
bool showMarkers,
QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_ui(new Ui::EventListDialog)
, m_columns(nullptr)
, m_model(new EventListDialogModel(ppmDtc, pdmDtc, ismDtc, this))
, m_detailData(nullptr)
, m_menuGroup(menuGroup)
, m_listEvents(false)
, m_flmIfc(flmIfc)
, m_session(session)
, m_logger(getLogger("EventList"))
{
m_ui->setupUi(this);
if (showMarkers)
{
m_ui->ltsDataView->setModel(m_model);
}
else
{
m_proxyModel = new EventListDialogProxyModel(this);
m_proxyModel->setSourceModel(m_model);
m_ui->ltsDataView->setModel(m_proxyModel);
}
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &EventListDialog::slotShowSelected);
connect(m_ui->ltsDataView, &LtsDataView::LtsDataView::signalSelectionChanged,
this, &EventListDialog::slotEnaDisa);
connect(this, &EventListDialog::signalAddNewEvents,
m_model, &EventListDialogModel::appendEventList);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Show, this, &EventListDialog::slotShowSelected);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Print, this, &EventListDialog::onPrint);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &EventListDialog::onConfigureColumns);
#ifndef LTS_DEBUG
addConcealedColumns({ EventListDialogModel::Id, EventListDialogModel::AesId, EventListDialogModel::ParticipantId,
EventListDialogModel::DamagePercentOld });
#endif
setUnchangeable();
}
EventListDialog::~EventListDialog()
{
DEBUG_LOG(m_logger) << "~EventListDialog";
if (m_proxyModel != nullptr)
m_proxyModel->setInvalid();
m_model->setInvalid();
delete m_ui;
delete m_columns;
}
void EventListDialog::retranslate()
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("Configuration"));
if (m_listEvents)
translate(m_ui, QString(), false, tr("All Events"));
else
translate(m_ui, QString(), false, tr("%1 Events").arg(m_model->rowCount()));
}
bool EventListDialog::init(DetailData *detailData, const LtsTimelineClassic::EventList &eventList, bool listEvents)
{
m_detailData = detailData;
m_listEvents = listEvents;
if (m_listEvents)
m_ui->label->setVisible(false);
if (eventList.isEmpty())
return false;
m_model->setData(eventList);
m_headerState = m_ui->ltsDataView->saveState();
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
m_ui->ltsDataView->treeView()->header()->setFirstSectionMovable(true);
m_ui->ltsDataView->searchView()->header()->setFirstSectionMovable(true);
#endif
initColumns();
return true;
}
void EventListDialog::addConcealedColumns(const QVector<int> &concealedColumns)
{
for (const int id : concealedColumns)
{
m_ui->ltsDataView->hideColumn(id);
if (!m_concealedColumns.contains(id))
m_concealedColumns += id;
}
}
void EventListDialog::initColumns()
{
const int colCount = m_model->columnCount();
if (colCount > 0)
{
m_headerColumns.clear();
QVector<ColumnInfo> columnInfos;
columnInfos.reserve(colCount);
const auto header = m_ui->ltsDataView->searchView()->header();
DEBUG_LOG(m_logger) << "concealed count: " << m_concealedColumns.length();
for (int visualIndex = 0; visualIndex < colCount; ++visualIndex)
{
DEBUG_LOG(m_logger) << visualIndex << " concealed? " << m_concealedColumns.contains(visualIndex);
if (m_concealedColumns.contains(visualIndex))
continue;
ColumnInfo ci;
ci.logicalIndex = header->logicalIndex(visualIndex);
ci.visualIndex = visualIndex;
ci.size = header->sectionSize(ci.logicalIndex);
ci.visible = !header->isSectionHidden(ci.logicalIndex);
ci.name = m_model->headerData(ci.logicalIndex, Qt::Orientation::Horizontal, Qt::DisplayRole).toString();
DEBUG_LOG(m_logger) << "InitColumns: Adding column " << ci.name <<
" with visual index = " << ci.visualIndex <<
", logical index = " << ci.logicalIndex;
m_headerColumns.insert(ci.name, ci.logicalIndex);
columnInfos += ci;
}
m_columns->deleteLater();
m_columns = new Timeline::EventListColumns(columnInfos, m_flmIfc, this);
connect(m_columns, &EventListColumns::accepted,
this, &EventListDialog::showColumns);
showColumns();
}
}
void EventListDialog::clearModel()
{
m_model->clear();
}
bool EventListDialog::appendEventList(const LtsTimelineClassic::EventList &eventList)
{
m_model->appendEventList(eventList);
retranslate();
return true;
}
void EventListDialog::slotEnaDisa()
{
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Show, (m_ui->ltsDataView->selectedRows().size() > 0));
}
void EventListDialog::slotShowSelected()
{
const QModelIndexList indexList = m_ui->ltsDataView->selectedRows();
if (!m_listEvents && indexList.count() > MAX_EVENTS)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("You selected too many events to show (> %1). Please deselect some.").arg(MAX_EVENTS));
return;
}
for (const QModelIndex &idx : indexList)
{
const LtsTimelineClassic::Event *event = m_model->eventList().at(idx.row());
if (event->uniqueId() > 0)
emit signalShowEventDetails(event);
}
}
void EventListDialog::onPrint()
{
LtsPrinting::printView(m_session, this, m_ui->ltsDataView->treeView());
}
void EventListDialog::onConfigureColumns()
{
initColumns();
m_columns->show();
}
void EventListDialog::showColumns()
{
if (!m_columns)
return;
const auto columnInfo = m_columns->currentColumnsState();
m_ui->ltsDataView->restoreState(m_headerState);
auto header = m_ui->ltsDataView->searchView()->header();
for (const auto &ci : columnInfo)
{
int oldVisualIndex = header->visualIndex(ci.logicalIndex);
DEBUG_LOG(m_logger) << "ShowColumns: Column " << ci.name
<< ", colVisible: " << ci.visible
<< ", logical index: " << ci.logicalIndex
<< ", old index: " << oldVisualIndex
<< ", new index: " << ci.visualIndex;
if (oldVisualIndex != ci.visualIndex)
header->moveSection(oldVisualIndex, ci.visualIndex);
header->setSectionHidden(ci.logicalIndex, !ci.visible);
if (ci.visible && ci.size > 0)
header->resizeSection(ci.logicalIndex, ci.size);
}
}
void EventListDialog::reInitEventList(const LtsTimelineClassic::EventList &eventList, qint64 startTime, qint64 endTime)
{
LtsTimelineClassic::EventList newEventList;
for (auto i = eventList.constBegin(); i != eventList.constEnd(); ++i)
{
LtsTimelineClassic::Event *e = (*i);
if (e->startTime() >= startTime && (e->startTime() + e->duration()) <= endTime)
newEventList += e;
}
DEBUG_LOG(m_logger) << "reInitEventList size = " << eventList.size();
DEBUG_LOG(m_logger) << "reInitEventList new size = " << newEventList.size();
m_model->clear();
m_model->setData(newEventList);
}
}
@@ -0,0 +1,83 @@
#pragma once
#include "logger.h"
#include <LtsTimelineClassic/EventList.h>
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <ParticipantManagement/Data/ppm_data_plugin.h>
#include <ProjectDataManagement/Data/pdm_data_plugin.h>
#include <InfrastructureManagement/Data/ism_data_plugin.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
namespace Ui
{
class EventListDialog;
}
namespace LtsTimelineClassic
{
class EventGraphic;
class Event;
}
namespace Timeline
{
class EventListDialogProxyModel;
class EventListDialogModel;
class DetailData;
class EventListColumns;
class EventListDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
EventListDialog(const QString &menuGroup, LtsSession::LtsSession *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
bool showMarkers = false,
QWidget *parent = nullptr);
~EventListDialog();
bool init(DetailData *detailData, const LtsTimelineClassic::EventList &eventList, bool listEvents);
bool appendEventList(const LtsTimelineClassic::EventList &eventList);
void clearModel();
void reInitEventList(const LtsTimelineClassic::EventList &eventList, qint64 startTime, qint64 endTime);
private:
void retranslate() override;
void initColumns();
void addConcealedColumns(const QVector<int> &concealedColumns);
Ui::EventListDialog *m_ui;
EventListColumns *m_columns;
EventListDialogModel *m_model;
DetailData *m_detailData;
QHash<QString, int> m_headerColumns;
QByteArray m_headerState;
QString m_menuGroup;
bool m_listEvents;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
LtsSession::LtsSession *m_session;
EventListDialogProxyModel *m_proxyModel { nullptr };
NGL::INGLLogger &m_logger;
QVector<int> m_concealedColumns;
signals:
void signalShowEventDetails(const LtsTimelineClassic::Event *event);
void signalAddNewEvents(const QVector<LtsTimelineClassic::Event *> &eventList);
private slots:
void showColumns();
void slotShowSelected();
void slotEnaDisa();
void onPrint();
void onConfigureColumns();
};
}
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EventListDialog</class>
<widget class="QWidget" name="EventListDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>824</width>
<height>445</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Exercise Management</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Selected event contained more than one event:</string>
</property>
</widget>
</item>
<item>
<widget class="LtsDataView::LtsDataView" name="ltsDataView">
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,206 @@
#include "tln_event_list_columns.h"
#include "ui_tln_event_list_columns.h"
#include "tln_event_list_model.h"
#include <FileManagement/flm_translation.h>
#include <LtsWidgets/lts_dialog.h>
#include <QSortFilterProxyModel>
#include <QAbstractItemModel>
#include <QColor>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
namespace Timeline
{
static inline QString colObjectName(int idx)
{
return QStringLiteral("Column_") + QString::number(idx);
}
EventListColumns::EventListColumns(const QVector<ColumnInfo> &columns,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
QWidget *parent)
: LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal )
, m_ui(new Ui::EventListColumns)
, m_flmIfc(flmIfc)
, m_columns(columns)
, m_logger(getLogger("EventListColumns"))
{
m_ui->setupUi(this);
connect(m_ui->pbOk, &QPushButton::clicked,
this, &EventListColumns::accept);
connect(m_ui->pbClose, &QPushButton::clicked,
this, &EventListColumns::reject);
connect(m_ui->pbLoad, &QPushButton::clicked,
this, &EventListColumns::load);
connect(m_ui->pbSave, &QPushButton::clicked,
this, &EventListColumns::save);
init();
}
EventListColumns::~EventListColumns()
{
delete m_ui;
}
QVector<ColumnInfo> EventListColumns::currentColumnsState() const
{
const auto children = m_ui->itemLayoutWidget->findChildren<EventListColumn*>();
QVector<ColumnInfo> result;
result.reserve(children.size());
for (const EventListColumn *elc : children)
result.push_back(elc->columnInfo());
std::sort(result.begin(), result.end(),
[](const ColumnInfo &a, const ColumnInfo &b)
{
return a.visualIndex < b.visualIndex;
});
return result;
}
void EventListColumns::init()
{
qDeleteAll(m_ui->itemLayoutWidget->findChildren<EventListColumn*>());
for (const auto &ci : qAsConst(m_columns))
{
EventListColumn *rtcItem = new EventListColumn(ci);
rtcItem->setObjectName(colObjectName(ci.logicalIndex));
m_ui->itemLayoutWidget->layout()->addWidget(rtcItem);
}
m_ui->lblConfiguration->setText(tr("No configuration file loaded"));
}
bool EventListColumns::load()
{
bool ret = false;
QByteArray content;
int fileId = m_flmIfc->loadFileContent(this, content, {FileManagement::FileType::Xml}, 0, FileManagement::toString(FileManagement::XmlType::TLNEventListConfiguration));
if (fileId > 0)
{
if (!m_flmIfc->isXmlType(content, FileManagement::toString(FileManagement::XmlType::TLNEventListConfiguration)))
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("Ok")}});
LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Invalid xml file content"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes,
texts);
}
else
{
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
const QJsonArray elcCols(obj.value(QStringLiteral("Columns")).toArray());
loadColumns(elcCols);
ret = true;
}
}
if (ret)
{
QString fileName = m_flmIfc->getFileName(fileId);
m_ui->lblConfiguration->setText(tr("Configuration file: %1").arg(fileName));
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Successfully loaded configuration file"));
}
else
{
m_ui->lblConfiguration->setText(tr("No configuration file loaded"));
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Could not load configuration file"));
}
return ret;
}
void EventListColumns::loadColumns(const QJsonArray &cols)
{
qDeleteAll(m_ui->itemLayoutWidget->findChildren<EventListColumn*>());
Timeline::ColumnInfo ci;
for (const auto &val : cols)
{
const QJsonObject obj = val.toObject();
ci.logicalIndex = obj.value(QStringLiteral("logicalIndex")).toInt();
ci.visualIndex = obj.value(QStringLiteral("visualIndex")).toInt();
ci.name = obj.value(QStringLiteral("name")).toString();
ci.size = obj.value(QStringLiteral("size")).toInt();
ci.visible = obj.value(QStringLiteral("visible")).toBool();
const QString objName = colObjectName(ci.logicalIndex);
EventListColumn *elc = m_ui->itemLayoutWidget->findChild<EventListColumn*>(objName);
if (elc)
{
ERROR_LOG(m_logger) << "Modifed Column: " << ci.visualIndex
<< ", " << ci.logicalIndex << ", " << ci.name
<< ", " << ci.visible << ", " << objName;
elc->setChecked(ci.visible);
}
else
{
ERROR_LOG(m_logger) << "New Column: " << ci.visualIndex
<< ", " << ci.logicalIndex << ", " << ci.name
<< ", " << ci.visible << ", " << objName;
elc = new EventListColumn(ci);
elc->setObjectName(objName);
m_ui->itemLayoutWidget->layout()->addWidget(elc);
}
}
}
bool EventListColumns::save()
{
int fileId = m_flmIfc->saveFileContent(this, FileManagement::FileType::Xml, 0, columnsToDoc(exportColumns()));
if (fileId > 0)
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
else
ERROR_LOG(m_logger) << "Could not save file in library ";
return (fileId > 0);
}
const QByteArray EventListColumns::columnsToDoc(const QJsonArray &cols)
{
QJsonObject obj;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::TLNEventListConfiguration);
obj[QStringLiteral("Columns")] = cols;
QJsonDocument doc(obj);
return doc.toJson(QJsonDocument::Compact);
}
const QJsonArray EventListColumns::exportColumns() const
{
QJsonArray result = QJsonArray();
const auto children = m_ui->itemLayoutWidget->findChildren<EventListColumn*>();
for (const EventListColumn *elc : children)
{
const auto &ci = elc->columnInfo();
DEBUG_LOG(m_logger) << "Saving column: " << ci.visualIndex << ", " << elc->text() << ", " << elc->isChecked();
QJsonObject elcObj;
elcObj[QStringLiteral("visualIndex")] = ci.visualIndex;
elcObj[QStringLiteral("logicalIndex")] = ci.logicalIndex;
elcObj[QStringLiteral("name")] = ci.name;
elcObj[QStringLiteral("size")] = ci.size;
elcObj[QStringLiteral("visible")] = ci.visible;
result.append(elcObj);
}
return result;
}
}
@@ -0,0 +1,84 @@
#pragma once
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include "logger.h"
#include <QCheckBox>
namespace Ui
{
class EventListColumns;
}
class QAbstractItemModel;
namespace Timeline
{
struct ColumnInfo
{
QString name;
int logicalIndex = 0;
int visualIndex = 0;
int size = 0;
bool visible = false;
};
class EventListColumn : public QCheckBox
{
Q_OBJECT
public:
explicit EventListColumn(const ColumnInfo &ci)
: QCheckBox(ci.name)
, m_ci(ci)
{
setChecked(ci.visible);
connect(this, &EventListColumn::clicked,
this, [this]() { m_ci.visible = isChecked(); });
}
const ColumnInfo &columnInfo() const { return m_ci; }
private:
ColumnInfo m_ci;
};
class EventListColumns : public LtsWidgets::LtsFramelessDialog
{
Q_OBJECT
public:
EventListColumns(const QVector<ColumnInfo> &columns,
const std::shared_ptr<FileManagement::ForeignGuiInterface> &flmIfc,
QWidget *parent = nullptr);
~EventListColumns();
QVector<ColumnInfo> currentColumnsState() const;
public slots:
bool save();
bool load();
private:
const QJsonArray exportColumns() const;
void init();
const QByteArray columnsToDoc(const QJsonArray &cols);
void loadColumns(const QJsonArray &cols);
private:
QString m_fileLoaded;
Ui::EventListColumns *m_ui;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
QVector<ColumnInfo> m_columns;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EventListColumns</class>
<widget class="QDialog" name="EventListColumns">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>368</width>
<height>234</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="lblShowColumns">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Columns:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblConfiguration">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>1</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>3</number>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<widget class="QWidget" name="itemLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>96</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>800</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>100</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="minimumSize">
<size>
<width>0</width>
<height>1</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>1</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="lineWidth">
<number>3</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pbSave">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbLoad">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbOk">
<property name="text">
<string>Ok</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClose">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>pbSave</tabstop>
<tabstop>pbClose</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,244 @@
#include "tln_event_list_model.h"
#include "detail_data.h"
#include <ngltools/ngltools_dtg.h>
#include <Services/ProjectDataManagement/pdm_translation.h>
#include <Services/ParticipantManagement/ppm_translation.h>
#include <Services/AreaEffectSimulation/aes_translation.h>
#include <QJsonObject>
#include <QDateTime>
namespace Timeline
{
EventListDialogModel::EventListDialogModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
QObject *parent)
: LtsWidgets::LtsAbstractTableModel<LtsTimelineClassic::Event *>({tr("Id"),
tr("Type"),
tr("Time"),
tr("Duration [s]", "Dauer in Sekunden"),
tr("Party"),
tr("Equipment Number"),
tr("Hierarchy"),
tr("Participant Id"),
tr("Aes Name"),
tr("Aes Type"),
tr("Building"),
tr("Charge Type"),
tr("Charge Remain"),
tr("Damage Percent"),
tr("Damage Percent Old"),
tr("Friendly Fire"),
tr("Gear Type"),
tr("Stream Name"),
tr("Vulnerability State")},
parent)
, m_ppmDtc(ppmDtc)
, m_pdmDtc(pdmDtc)
, m_ismDtc(ismDtc)
, m_logger(getLogger("EventListModel"))
{}
QVariant EventListDialogModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index) || m_invalid)
return QVariant();
LtsTimelineClassic::Event *event = m_vecData.at(index.row());
const QJsonObject &obj = event->detailData();
switch (index.column())
{
case EventListDialogModel::Columns::Id:
return event->uniqueId();
case EventListDialogModel::Columns::Type:
{
if (event->typeId() == markerTypeId )
return tr("Marker");
return ProjectDataManagement::toString(static_cast<ProjectDataManagement::EventType::type>(event->typeId()));
}
case EventListDialogModel::Columns::Time:
return QDateTime::fromMSecsSinceEpoch(event->startTime());
case EventListDialogModel::Columns::Duration:
return (event->duration() / 1000);
case EventListDialogModel::Columns::Party:
{
if (event->typeId() == ProjectDataManagement::EventType::HitBuilding)
break;
return ParticipantManagement::trPartyName(m_ppmDtc->party(event->partyId()).name());
}
case EventListDialogModel::Columns::EquipNo:
{
if (event->typeId() == ProjectDataManagement::EventType::HitBuilding)
break;
return event->equipmentId();
}
case EventListDialogModel::Columns::Hierarchy:
return m_ppmDtc->hierarchyFromParticipant(event->playerId());
case EventListDialogModel::Columns::ParticipantId:
return event->playerId();
case EventListDialogModel::AesType:
{
const auto ele = obj.value(QLatin1String("AesType"));
if (!ele.isDouble())
return QVariant();
const int aesTypeId = ele.toInt();
return AreaEffectSimulation::toString(static_cast<AreaEffectSimulation::AesType_def::type>(aesTypeId));
}
case EventListDialogModel::AesId:
{
const auto ele = obj.value(QLatin1String("AesName"));
if (ele.isString())
return ele.toString();
const auto ele2 = obj.value(QLatin1String("AesId"));
return ele2.isDouble() ? QVariant(ele.toInt()) : QVariant();
}
case EventListDialogModel::Building:
{
const auto ele = obj.value(QLatin1String("MainStructureElementId"));
if (!ele.isDouble())
return QVariant();
int buildingId = ele.toInt();
if (buildingId > 0)
return m_ismDtc->getBuildingDisplayName(buildingId);
return QVariant();
}
case EventListDialogModel::ChargeType:
{
int chargeTypeId = obj.value(QLatin1String("OriginatorChargeTypeId")).toInt();
if (chargeTypeId <= 0)
chargeTypeId = obj.value(QLatin1String("ChargeTypeId")).toInt();
if (chargeTypeId <= 0)
return QVariant();
return m_pdmDtc->trChargeTypeShortName(chargeTypeId);
}
case EventListDialogModel::ChargeRemain:
{
const auto ele = obj.value(QLatin1String("Remain"));
if (!ele.isDouble())
return QVariant();
return ele.toInt();
}
case EventListDialogModel::DamagePercent:
{
const auto ele = obj.value(QLatin1String("damagePercent"));
if (!ele.isDouble())
return QVariant();
return ele.toInt();
}
case EventListDialogModel::DamagePercentOld:
{
const auto ele = obj.value(QLatin1String("damagePercentOld"));
if (!ele.isDouble())
return QVariant();
return ele.toInt();
}
case EventListDialogModel::FriendlyFire:
{
const auto ele = obj.value(QLatin1String("FriendlyFire"));
if (!ele.isBool())
return QVariant();
return ele.toBool();
}
case EventListDialogModel::GearType:
{
int gearTypeId = obj.value(QLatin1String("GearTypeId")).toInt();
if (gearTypeId <= 0)
return QVariant();
return m_pdmDtc->trGearTypeName(gearTypeId);
}
case EventListDialogModel::StreamName:
{
const auto ele = obj.value(QLatin1String("streamName"));
if (!ele.isString())
return QVariant();
return ele.toString();
}
case EventListDialogModel::VulnerabilityState:
{
const auto ele = obj.value(QLatin1String("VulnerabilityState"));
if (!ele.isDouble())
return QVariant();
const int vId = ele.toInt();
return ProjectDataManagement::toString(static_cast<ProjectDataManagement::VulnerabilityState_def::type>(vId));
}
default:
break;
}
return QVariant();
}
void EventListDialogModel::appendEventList(const QVector<LtsTimelineClassic::Event *> &eventList)
{
for (const auto &event : eventList)
{
if (!m_vecData.contains(event))
insertRow(event);
}
}
void EventListDialogProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<EventListDialogModel*>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
}
bool EventListDialogProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
if (!m_sourceModel ||
source_left.column() != source_right.column() ||
!source_left.isValid() ||
!source_right.isValid() ||
m_invalid)
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
const auto &dataLeft = m_sourceModel->m_vecData.at(source_left.row());
const auto dataRight = m_sourceModel->m_vecData.at(source_right.row());
switch (source_left.column())
{
case EventListDialogModel::Time:
return dataLeft->startTime() < dataRight->startTime();
case EventListDialogModel::EquipNo:
return dataLeft->equipmentId() < dataRight->equipmentId();
default:
break;
}
return LtsWidgets::LtsColumnFilterProxyModel::lessThan(source_left, source_right);
}
bool EventListDialogProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!m_sourceModel || source_parent.isValid() || source_row < 0 || source_row >= m_sourceModel->rowCount() || m_invalid)
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
LtsTimelineClassic::Event *event = m_sourceModel->m_vecData.at(source_row);
if (event->typeId() == markerTypeId)
return false;
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
}
@@ -0,0 +1,86 @@
#pragma once
#include <LtsTimelineClassic/Event.h>
#include <ParticipantManagement/Data/ppm_data_plugin.h>
#include <ProjectDataManagement/Data/pdm_data_plugin.h>
#include <InfrastructureManagement/Data/ism_data_plugin.h>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
namespace Timeline
{
class EventListDialogModel final : public LtsWidgets::LtsAbstractTableModel<LtsTimelineClassic::Event *>
{
Q_OBJECT
public:
enum Columns
{
Id,
Type,
Time,
Duration,
Party,
EquipNo,
Hierarchy,
ParticipantId,
AesId,
AesType,
Building,
ChargeType,
ChargeRemain,
DamagePercent,
DamagePercentOld,
FriendlyFire,
GearType,
StreamName,
VulnerabilityState,
Count
};
explicit EventListDialogModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<ProjectDataManagement::Interface::Dtc> &pdmDtc,
const std::shared_ptr<InfrastructureManagement::Interface::Dtc> &ismDtc,
QObject *parent = nullptr);
const QVector<LtsTimelineClassic::Event *> &eventList() const { return m_vecData; }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void setInvalid() { m_invalid = true; }
public slots:
void appendEventList(const QVector<LtsTimelineClassic::Event *> &eventList);
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<InfrastructureManagement::Interface::Dtc> m_ismDtc;
bool m_invalid = false;
NGL::INGLLogger &m_logger;
friend class EventListDialogProxyModel;
};
class EventListDialogProxyModel final : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
void setSourceModel(QAbstractItemModel *sourceModel) override;
void setInvalid() { m_invalid = true; }
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
EventListDialogModel *m_sourceModel = nullptr;
bool m_invalid = false;
};
}
@@ -0,0 +1,320 @@
#include "tln_legend.h"
#include "ui_tln_legend.h"
#include "detail_data.h"
#include "tln_dialog_model.h"
#include <LtsTimelineClassic/Event.h>
#include <LtsTimelineClassic/EventGraphic.h>
#include <LtsUtilsSettings/settings.h>
#include <ProjectDataManagement/pdm_enums.hpp>
#include <ProjectDataManagement/pdm_translation.h>
#include <QLabel>
#include <QImage>
#include <QPixmap>
#include <QPainter>
namespace Timeline
{
TimelineLegendDialog::TimelineLegendDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ui(new Ui::TimelineLegendDialog)
, m_logger(getLogger("TimelineLegendDialog"))
{
m_ui->setupUi(this);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->hide();
connect(m_ui->cbCheckAll, &QCheckBox::toggled,
this, [this](bool toggled)
{
const auto cbList = findChildren<QCheckBox *>();
for (QCheckBox *cb : cbList)
{
if (cb == m_ui->cbCheckAll)
continue;
cb->setChecked(toggled);
}
});
}
TimelineLegendDialog::~TimelineLegendDialog()
{
delete m_ui;
}
void TimelineLegendDialog::retranslate()
{
translate(m_ui, tr("Timeline Legend"));
}
void TimelineLegendDialog::setActiveEventTypeIds(const QSet<int> &activeEventTypeIds)
{
setUnchangeable();
const QList<QCheckBox *> cbs(findChildren<QCheckBox *>());
for (QCheckBox *cb : cbs)
cb->setChecked(false);
for (int activeEventType : activeEventTypeIds)
{
QCheckBox *cb = checkBox(activeEventType);
if (cb != nullptr)
cb->setChecked(true);
else
WARNING_LOG(m_logger) << "cb for event type " << activeEventType << " not found!";
}
setUnchangeable(false);
}
QVector<ProjectDataManagement::EventType> TimelineLegendDialog::possibleEvents()
{
QVector<ProjectDataManagement::EventType> ret
({
ProjectDataManagement::EventType::Hit,
ProjectDataManagement::EventType::WeaponAssignment,
ProjectDataManagement::EventType::BiteMessage,
ProjectDataManagement::EventType::FireEvent,
ProjectDataManagement::EventType::HitBuilding,
ProjectDataManagement::EventType::Manipulation,
ProjectDataManagement::EventType::CameraVideo,
ProjectDataManagement::EventType::RadioCnr,
ProjectDataManagement::EventType::RadioTvc,
ProjectDataManagement::EventType::HitEffectSimulation,
ProjectDataManagement::EventType::CrossLocalBorderline,
ProjectDataManagement::EventType::CrossGlobalBorderline,
});
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
if (ps->value(QStringLiteral("tln"),
QStringLiteral("showEffectSimulationEvents")).toBool())
{
ret += ProjectDataManagement::EventType::MineArea;
ret += ProjectDataManagement::EventType::DangerArea;
ret += ProjectDataManagement::EventType::FunctionalArea;
ret += ProjectDataManagement::EventType::MineCorridor;
ret += ProjectDataManagement::EventType::Borderline;
if (ps->value(QStringLiteral("aes"),
QStringLiteral("enableNuclearContaminations")).toBool())
ret += ProjectDataManagement::EventType::NContamination;
if (ps->value(QStringLiteral("aes"),
QStringLiteral("enableNuclearContaminations")).toBool() ||
ps->value(QStringLiteral("aes"),
QStringLiteral("enableNuclearContaminations")).toBool())
ret += ProjectDataManagement::EventType::BCContamination;
}
if (ps->value(QStringLiteral("tln"),
QStringLiteral("showEnterLeaveEvents")).toBool())
{
ret += ProjectDataManagement::EventType::EnterDangerArea;
ret += ProjectDataManagement::EventType::LeaveDangerArea;
ret += ProjectDataManagement::EventType::EnterMineArea;
ret += ProjectDataManagement::EventType::LeaveMineArea;
ret += ProjectDataManagement::EventType::EnterFunctionalArea;
ret += ProjectDataManagement::EventType::LeaveFunctionalArea;
if (ps->value(QStringLiteral("aes"),
QStringLiteral("enableNuclearContaminations")).toBool())
{
ret += ProjectDataManagement::EventType::EnterNuclear;
ret += ProjectDataManagement::EventType::LeaveNuclear;
}
}
if (ps->value(QStringLiteral("aes"),
QStringLiteral("enableGasPipes")).toBool())
{
ret += ProjectDataManagement::EventType::GasPipe;
}
const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"),
QStringLiteral("HasPvSan"));
if (showPvSan)
ret += ProjectDataManagement::EventType::Sanitation;
return ret;
}
static int categoryFromEventType(ProjectDataManagement::EventType et)
{
switch (et.underlying())
{
case ProjectDataManagement::EventType::Unknown:
return 0;
case ProjectDataManagement::EventType::Hit:
case ProjectDataManagement::EventType::WeaponAssignment:
case ProjectDataManagement::EventType::BiteMessage:
case ProjectDataManagement::EventType::FireEvent:
case ProjectDataManagement::EventType::FriendlyFire:
case ProjectDataManagement::EventType::Manipulation:
return 1;
case ProjectDataManagement::EventType::CameraVideo:
case ProjectDataManagement::EventType::RadioCnr:
case ProjectDataManagement::EventType::RadioTvc:
return 5;
case ProjectDataManagement::EventType::HitBuilding:
case ProjectDataManagement::EventType::HitEffectSimulation:
case ProjectDataManagement::EventType::HitMine:
case ProjectDataManagement::EventType::HitN:
case ProjectDataManagement::EventType::HitB:
case ProjectDataManagement::EventType::HitC:
case ProjectDataManagement::EventType::HitGasPipe:
return 2;
case ProjectDataManagement::EventType::EnterDangerArea:
case ProjectDataManagement::EventType::LeaveDangerArea:
case ProjectDataManagement::EventType::EnterMineArea:
case ProjectDataManagement::EventType::LeaveMineArea:
case ProjectDataManagement::EventType::CrossLocalBorderline:
case ProjectDataManagement::EventType::EnterFunctionalArea:
case ProjectDataManagement::EventType::LeaveFunctionalArea:
case ProjectDataManagement::EventType::EnterNuclear:
case ProjectDataManagement::EventType::LeaveNuclear:
case ProjectDataManagement::EventType::CrossGlobalBorderline:
case ProjectDataManagement::EventType::Sanitation:
return 3;
case ProjectDataManagement::EventType::MineArea:
case ProjectDataManagement::EventType::NContamination:
case ProjectDataManagement::EventType::BCContamination:
case ProjectDataManagement::EventType::DangerArea:
case ProjectDataManagement::EventType::FunctionalArea:
case ProjectDataManagement::EventType::MineCorridor:
case ProjectDataManagement::EventType::Borderline:
case ProjectDataManagement::EventType::GasPipe:
return 6;
case ProjectDataManagement::EventType::TechnicalArea:
case ProjectDataManagement::EventType::EquipmentErrorReport:
case ProjectDataManagement::EventType::EmergencyCall:
return 0;
}
Q_ASSERT(false);
return 0;
}
bool TimelineLegendDialog::init(DDSTimelineModel *model, const QSet<int> &activeEventTypeIds)
{
struct WidgetSortHelper
{
QLabel *lbl = nullptr;
QCheckBox *cbx = nullptr;
ProjectDataManagement::EventType et = ProjectDataManagement::EventType::Unknown;
};
QImage p(16, 24, QImage::Format_ARGB32);
QColor c;
LtsTimelineClassic::Event::EventPaintFunc paintFunc;
WidgetSortHelper wsh;
const auto events = possibleEvents();
std::vector<WidgetSortHelper> helperCont;
helperCont.reserve(events.size());
for (const ProjectDataManagement::EventType eventType : events)
{
model->setColorPaintFun(paintFunc, c, eventType.underlying());
if (paintFunc == nullptr)
{
WARNING_LOG(m_logger) << "No draw function for event " << eventType;
Q_ASSERT(false);
continue;
}
p.fill(Qt::transparent);
QPainter pp(&p);
pp.setRenderHint(QPainter::Antialiasing);
pp.setBrush(QBrush(c));
paintFunc(&pp, p.rect().adjusted(0, 0, -1, -1));
wsh.lbl = new QLabel(this);
wsh.lbl->setPixmap(QPixmap::fromImage(p));
wsh.et = eventType;
wsh.cbx = new QCheckBox(ProjectDataManagement::toString(eventType), this);
wsh.cbx->setObjectName(checkBoxName(eventType));
wsh.cbx->setChecked(activeEventTypeIds.contains(eventType.underlying()));
wsh.cbx->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
helperCont.push_back(wsh);
}
std::sort(helperCont.begin(), helperCont.end(), [](const WidgetSortHelper &a, const WidgetSortHelper &b)
{
const auto et1 = categoryFromEventType(a.et);
const auto et2 = categoryFromEventType(b.et);
if (et1 != et2)
return et1 < et2;
return a.cbx->text() < b.cbx->text();
});
int curGridRow = 1;
for (const auto &ele : helperCont)
{
m_ui->gridLayout->addWidget(ele.lbl, curGridRow, 0);
m_ui->gridLayout->addWidget(ele.cbx, curGridRow, 1);
m_ui->gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), curGridRow, 2);
++curGridRow;
}
m_ui->gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding), curGridRow, 0);
return true;
}
bool TimelineLegendDialog::apply()
{
QSet<int> activeEventTypeIds;
const auto events = possibleEvents();
for (const ProjectDataManagement::EventType eventType : events)
{
if (checkBox(eventType)->isChecked())
activeEventTypeIds.insert(eventType.underlying());
}
emit signalEventTypesChanged(activeEventTypeIds);
return false;
}
}
@@ -0,0 +1,51 @@
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <ProjectDataManagement/pdm_enums.hpp>
#include "logger.h"
namespace Ui
{
class TimelineLegendDialog;
}
namespace Timeline
{
class DDSTimelineModel;
class TimelineLegendDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit TimelineLegendDialog(QWidget *parent = nullptr);
~TimelineLegendDialog();
bool apply() override;
bool init(DDSTimelineModel *model, const QSet<int> &activeEventTypeIds);
void setActiveEventTypeIds(const QSet<int> &activeEventTypeIds);
static QVector<ProjectDataManagement::EventType> possibleEvents();
signals:
void signalEventTypesChanged(const QSet<int> &activeEventTypeIds);
private:
void retranslate() override;
static QString checkBoxName(int eventTypeId) { return QStringLiteral("CheckBoxEvent%1").arg(eventTypeId); }
static QString checkBoxName(ProjectDataManagement::EventType eventType) { return checkBoxName(eventType.underlying()); }
QCheckBox *checkBox(int eventTypeId) { return findChild<QCheckBox *>(checkBoxName(eventTypeId)); }
QCheckBox *checkBox(ProjectDataManagement::EventType eventType) { return checkBox(eventType.underlying()); }
private:
Ui::TimelineLegendDialog *m_ui;
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TimelineLegendDialog</class>
<widget class="QWidget" name="TimelineLegendDialog">
<property name="windowTitle">
<string notr="true">Timeline View</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="cbCheckAll">
<property name="text">
<string>Check all</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,505 @@
#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>
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)
{
if (!m_event->positionValid())
{
WARNING_LOG(m_logger) << "event has no valid position, skip focusOnMap";
return;
}
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();
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) );
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;
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();
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())
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())
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."));
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;
for (const DetailData::GetDetailDataForAttributeResult &attributeDetail : result)
{
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)
{
attributeTypeText = attributeDetail.attributeType;
attributeValueText = QStringLiteral("%1 (%2)").arg(tr("<unknown>")).arg(attributeDetail.attributeValueId);
}
else if (attributeDetail.requestResult == DetailData::RequestResult::InvalidAttributeType)
{
DEBUG_LOG(m_logger) << "Unhandled attribute " << attributeDetail.attributeTypeId << " - skipping";
continue;
}
else
{
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;
}
}
else
{
attributeTypeText = attributeDetail.attributeType;
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);
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"))
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";
}
}
@@ -0,0 +1,90 @@
#pragma once
#include "tln_view_gui_plugin.h"
#include <LtsWidgets/lts_dialog.h>
#include <LtsSession/lts_session.h>
#include <LtsTimelineClassic/Event.h>
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
#include <Plugins/FilterManagement/flt_participant_plugin_interface.h>
#include <Plugins/FilterManagement/flt_aes_plugin_interface.h>
#include <Plugins/FilterManagement/flt_building_cmpnt_plugin_interface.h>
#include <MarkerManagement/mrk_dtc.h>
namespace Ui
{
class ShowDetailsDialog;
}
namespace AudioVideoManagement
{
class StreamNameMapping;
}
namespace Timeline
{
class DetailData;
class ShowDetailsDialog : public LtsWidgets::LtsDialog
{
Q_OBJECT
public:
explicit ShowDetailsDialog(QWidget *parent = nullptr);
~ShowDetailsDialog();
bool 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);
void retranslate() override;
private slots:
void slotStartReplay();
void slotStartPlayback();
void slotShowMarker();
void slotFocusOnMap();
void updateMarker();
private:
bool hasNameAndEndTime() const;
bool getStreamNameAndEndTime(QString &streamName, qint64 &endTime, bool silent = false) const;
void setButtonDisabled(QPushButton *button, QToolButton *warningButton, const QString &reasonMessage, bool hide = false);
bool isMarkerAudioVideo() const;
static bool isAvsCapable(const LtsTimelineClassic::Event *event);
static bool isHitEventType(int eventTypeId);
static bool isAvEventType(int eventTypeId);
static bool isAudioEventType(int eventTypeId);
QString m_eventType;
Ui::ShowDetailsDialog *m_ui{nullptr};
const LtsTimelineClassic::Event *m_event{nullptr};
QPointer<LtsSession::LtsSession> m_replayAppSession;
std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> m_avmIfc;
std::shared_ptr<MarkerManagement::ForeignGuiInterface> m_mrkIfc;
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> m_fltParticipantIfc;
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> m_fltAesIfc;
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> m_fltBuildingComponentIfc;
AudioVideoManagement::StreamNameMapping *m_streamNameMapping{nullptr};
std::shared_ptr<MarkerManagement::Interface::Dtc> m_mrkDtc;
LtsSession::LtsSessionDataDds *m_session{nullptr};
NGL::INGLLogger &m_logger;
};
}
@@ -0,0 +1,304 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ShowDetailsDialog</class>
<widget class="QWidget" name="ShowDetailsDialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<height>451</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Exercise Management</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="lblEventType">
<property name="text">
<string notr="true">&lt;Event Type&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblEquipNo">
<property name="toolTip">
<string>Folder Name</string>
</property>
<property name="text">
<string>Equip. No.:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblTime">
<property name="text">
<string>Event Time:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblValueEquipNo">
<property name="text">
<string notr="true">...</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblValueEventTime">
<property name="text">
<string notr="true">...</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QToolButton" name="tbPlayback">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Dark/resources/rme_dark_style.qrc">
<normaloff>:/style/warning.svg</normaloff>:/style/warning.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbPlayback">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Plays the audio and/or video clip assoociated to the event in the replay application, in a audio/video dialog.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Start Playback</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QToolButton" name="tbFocus">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Dark/resources/rme_dark_style.qrc">
<normaloff>:/style/warning.svg</normaloff>:/style/warning.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbFocus">
<property name="text">
<string>Focus on map</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QToolButton" name="tbReplay">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Dark/resources/rme_dark_style.qrc">
<normaloff>:/style/warning.svg</normaloff>:/style/warning.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbStartReplay">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Sets the replay application back to the time the event occured and focuses the event on the map. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Start Replay</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QToolButton" name="tbMarker">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Dark/resources/rme_dark_style.qrc">
<normaloff>:/style/warning.svg</normaloff>:/style/warning.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbShowMarker">
<property name="text">
<string>Show Marker</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="debugWidget" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="lblDebug">
<property name="text">
<string notr="true">&lt;font color='#aebac6'&gt;Debug:&lt;/font&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string notr="true">Position:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblPos">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPlainTextEdit" name="pteDetailDataTest">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="../../../Styles/Dark/resources/rme_dark_style.qrc"/>
</resources>
<connections/>
</ui>
@@ -0,0 +1,160 @@
#include "EventFilter/FilterWindow.h"
#include "tln_view_gui_plugin.h"
#include "tln_dialog.h"
#include "logger.h"
#include <stdlib.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_manager.h>
#include <LtsSession/lts_session_data.h>
#include <QTimer>
namespace Timeline
{
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("View"))
{}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getForeignDataInterface<TimeLineManagement::DataInterface>(m_eemForeign))
return false;
if (!m_session->getDtc<MarkerManagement::DataInterface>(m_mrkDtc))
return false;
if (!m_session->getDtc<ExerciseManagement::DataInterface>(m_exmDtc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmIfc))
return false;
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignParticipantInfoGuiInterface>(m_ppmInfoIfc))
return false;
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
return false;
if (!m_session->getForeignDataInterface_NEW(m_avmDataIfc))
WARNING_LOG(m_logger) << "no avm data ifc, no stream name mapping";
if (!m_session->getForeignDataInterface<SituationReplayManagement::DataInterface>(m_srmDataIfc))
WARNING_LOG(m_logger) << "no srm data ifc, no situation replay app";
if (!m_session->getDtc<SituationReplayManagement::DataInterface>(m_coreDtc))
WARNING_LOG(m_logger) << "no core dtc, no situation replay app";
if (!m_session->getForeignGuiInterface<AudioVideoManagement::ForeignMenuEditGuiInterface>(m_avmIfc))
WARNING_LOG(m_logger) << "Timeline Gui Plugin: no avm ifc";
if (!m_session->getForeignGuiInterface<MarkerManagement::ForeignGuiInterface>(m_mrkIfc))
WARNING_LOG(m_logger) << "Timeline Gui Plugin: no mrk ifc";
if (!m_session->getForeignGuiInterface<FilterManagement::ForeignFltParticipantGuiInterface>(m_fltParticipantIfc))
WARNING_LOG(m_logger) << "Timeline Gui Plugin: no flt Part ifc";
if (!m_session->getForeignGuiInterface<FilterManagement::ForeignAesGuiInterface>(m_fltAesIfc))
WARNING_LOG(m_logger) << "Timeline Gui Plugin: no flt Aes ifc";
if (!m_session->getForeignGuiInterface<FilterManagement::ForeignFltBuildingComponentGuiInterface>(m_fltBuildingComponentIfc))
WARNING_LOG(m_logger) << "Timeline Gui Plugin: no flt BuildingComponent ifc";
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_eemForeign = nullptr;
m_mrkDtc = nullptr;
m_exmDtc = nullptr;
m_ppmDtc = nullptr;
m_flmIfc = nullptr;
m_ppmInfoIfc = nullptr;
m_srmDataIfc = nullptr;
m_coreDtc = nullptr;
m_avmIfc = nullptr;
m_mrkIfc = nullptr;
m_avmDataIfc = nullptr;
m_pdmDtc = nullptr;
m_fltParticipantIfc = nullptr;
m_fltAesIfc = nullptr;
m_fltBuildingComponentIfc = nullptr;
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
{
LtsWidgets::PluginData plData;
plData.menuGroup = menuGroup();
plData.menuText = tr("Timeline");
plData.identifier = QLatin1String("tlnView");
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.menuIcon = QIcon(QLatin1String("icon:timeline.svg"));
if (getFlags().testFlag(LtsAppDescriptor::PluginInfo::Flag::MAIN))
{
plData.layoutArea = LtsWidgets::LayoutArea::eMainTab;
plData.createInstant = LtsWidgets::CreateInstantType::CreateInstantAndDiscardAction;
plData.createWidgetFunc = [this](QWidget *)
{
return onShowTimelineViewDialog(true);
};
}
else
{
plData.layoutArea = LtsWidgets::LayoutArea::eDialogTab;
plData.createWidgetFunc = [this](QWidget *)
{
return onShowTimelineViewDialog(false);
};
}
ret.append(plData);
}
return ret;
}
QString InterfaceImpl::menuGroup() const
{
return tr("Timeline");
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowTimelineViewDialog(bool isMain)
{
std::shared_ptr<InfrastructureManagement::Interface::Dtc> ismDtc;
if (!m_session->getDtc<InfrastructureManagement::DataInterface>(ismDtc))
{
new LtsWidgets::LtsMessageDialogNew(m_session->baseLayoutWidget(), tr("The Infrastructure Management is not available!"), tr("Cannot open Timeline"));
return nullptr;
}
LtsWidgets::ButtonCombination buttonCombo = LtsWidgets::ButtonCombination::CloseOnly;
AudioVideoManagement::StreamNameMapping *streamNameMapping = nullptr;
if (m_avmDataIfc)
streamNameMapping = m_avmDataIfc->streamNameMapping();
return LtsWidgets::initDialog(new TimelineViewDialog(menuGroup(), buttonCombo, isMain, nullptr),
m_eemForeign, m_mrkDtc, m_exmDtc, m_flmIfc, m_ppmDtc,
m_ppmInfoIfc, m_avmIfc, m_mrkIfc,m_srmDataIfc, m_coreDtc,
m_pdmDtc, ismDtc, m_fltParticipantIfc, m_fltAesIfc, m_fltBuildingComponentIfc, m_session,
streamNameMapping);
}
}
@@ -0,0 +1,87 @@
#pragma once
#include <Plugins/Timeline/tln_view_gui_plugin_interface.h>
#include <Plugins/Timeline/tln_data_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Common/ProjectConfig/project_defines.h>
#include <Plugins/MarkerManagement/mrk_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participant_info_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Plugins/AudioVideoManagement/avm_menu_edit_gui_plugin_interface.h>
#include <Plugins/MarkerManagement/mrk_gui_plugin_interface.h>
#include <Plugins/SituationReplayManagement/srm_data_plugin_interface.h>
#include <Plugins/AudioVideoManagement/avm_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/InfrastructureManagement/ism_data_plugin_interface.h>
#include <Plugins/FilterManagement/flt_participant_plugin_interface.h>
#include <Plugins/FilterManagement/flt_aes_plugin_interface.h>
#include <Plugins/FilterManagement/flt_building_cmpnt_plugin_interface.h>
#include <Plugins/AreaEffectSimulation/aes_data_plugin_interface.h>
namespace Timeline
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:tln.view")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QLatin1String("TimelineGuiPlugin"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise || partition == IDL::PartitionType::Replay;
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
QVector<LtsWidgets::PluginData> getActions() override;
QString menuGroup() const override;
bool availableInPartition(IDL::PartitionType partition) const override { return partition == IDL::PartitionType::Exercise || partition == IDL::PartitionType::Replay; }
bool fetchInterfaces() override;
void clearInterfaces() override;
private:
LtsWidgets::LtsDialog *onShowTimelineViewDialog(bool isMain);
std::shared_ptr<Core::Interface::Dtc> m_coreDtc;
std::shared_ptr<ExerciseManagement::Interface::Dtc> m_exmDtc;
std::shared_ptr<MarkerManagement::Interface::Dtc> m_mrkDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<AudioVideoManagement::DataInterface> m_avmDataIfc;
std::shared_ptr<TimeLineManagement::ForeignDataInterface> m_eemForeign;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmIfc;
std::shared_ptr<ParticipantManagement::ForeignParticipantInfoGuiInterface> m_ppmInfoIfc;
std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> m_avmIfc;
std::shared_ptr<MarkerManagement::ForeignGuiInterface> m_mrkIfc;
std::shared_ptr<SituationReplayManagement::ForeignDataInterface> m_srmDataIfc;
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> m_fltParticipantIfc;
std::shared_ptr<FilterManagement::ForeignAesGuiInterface> m_fltAesIfc;
std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> m_fltBuildingComponentIfc;
};
}