Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
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)
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for attributes for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
//#include "FilterWindow.h" // for debug messagebox
|
||||
#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) // create a widget, suitable for the attribute
|
||||
{
|
||||
AbstractAttributeWidget *resultWidget = nullptr;
|
||||
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
int attributeUIType = detailData->attributeUITypeLookup.getUIType(concreteAttributeType);
|
||||
|
||||
if (attributeUIType == -1) // not found? abort!
|
||||
return nullptr;
|
||||
|
||||
//WARNING_LOG(m_logger) << "createAttributeUIWidget: for attributeType " << attributeType << " with string " << initialValue << " and attribute ui type " << attributeUIType;
|
||||
|
||||
const DetailData::AttributeParameterLookup::ParameterMap &pm = detailData->attributeParameterLookup.getParameterMap(concreteAttributeType); //const DetailData::UIInitialValuesLookup::ParameterValuesMap& pvm = filterData->uiInitialValuesLookup.getUIInitialValuesMap(attributeUIType); // initial values to be used to create widgets with intiaial values.....
|
||||
|
||||
switch (attributeUIType)
|
||||
{
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_COMBO_BOX: // do not use pm !
|
||||
{
|
||||
resultWidget = new ComboBox(detailData, concreteAttributeType, eventType, initialValue); // get the combobox for the attribute (which is then filled with possible values)
|
||||
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) // || prefix.isEmpty() || suffix.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "createAttributeUIWidget: !minb (" << minb << ") || !maxb (" << maxb << ")"; // || prefix.isEmpty ("<<prefix.isEmpty()<<") || suffix.isEmpty ("<<suffix.isEmpty()<<")" << ;
|
||||
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); // set by zwmstl_timelineFilterData TODO: initial value !
|
||||
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); // set by zwmstl_timelineFilterData TODO: initial value !
|
||||
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); // 1 = 'true'-value from the list (must not have that wordly negative sound)
|
||||
break;
|
||||
}
|
||||
|
||||
case DetailData::ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET:
|
||||
{
|
||||
TimeRangeWidget *trw = new TimeRangeWidget(detailData, initialValue); // update parameter lists filled by EventFilter-using component for specific widgets
|
||||
detailData->createRetrieveCurrentTimeCallback(trw->m_edit1);
|
||||
detailData->createRetrieveCurrentTimeCallback(trw->m_edit2);
|
||||
resultWidget = trw;
|
||||
break;
|
||||
}
|
||||
|
||||
default: // invalid attribute type!
|
||||
{
|
||||
WARNING_LOG(m_logger) << "createAttributeUIWidget: invalid attribute type #" << attributeUIType << "!";
|
||||
//return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//resultWidget->setStyleSheet("background-color:#CC9B97;"); // layer 3
|
||||
return resultWidget;
|
||||
}
|
||||
|
||||
void EditingModeUI::addAttributeContainer(int eventType, const QString &initialValue)
|
||||
{
|
||||
//attributeValuesLayout->addWidget(createAttributeUIWidget(attributeType), 0, Qt::AlignTop);
|
||||
|
||||
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(); // set focus to new widget
|
||||
}
|
||||
|
||||
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; // contains the filter text + widget to delete whole filter
|
||||
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); // add layout to widget
|
||||
pbAddAttributeContainer = new QPushButton(tr("Add Value"));
|
||||
pbAddAttributeContainer->setPalette(QPalette(QColor("green")));
|
||||
|
||||
// add all widgets to editing mode main widget
|
||||
setLayout(editingModeLayout);
|
||||
editingModeLayout->addWidget(filterTextWidget, 0, Qt::AlignTop);
|
||||
|
||||
// horizontal line after filter text
|
||||
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); // add attribute values "list" to this, so it can be searched through for attribute values
|
||||
}
|
||||
|
||||
EditingModeUI::~EditingModeUI()
|
||||
{
|
||||
const auto children = findChildren<AbstractAttributeWidget*>();
|
||||
for (auto child : children)
|
||||
child->disconnect(this);
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for attributes for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#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()); // 0 = default val (do not set -1 invalid !)
|
||||
|
||||
QLabel *lbFilterText;
|
||||
QPushButton *pbDelete;
|
||||
QVBoxLayout *attributeValuesLayout;
|
||||
QPushButton *pbAddAttributeContainer; // does not end this mode, adds an attribute container
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for events for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "../detail_data.h"
|
||||
#include "AttributeSelectionModeUI.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
QComboBox *SelectionModeUI::createAttributesComboBox(int eventType)
|
||||
{
|
||||
QComboBox *cbAttributes = new QComboBox();
|
||||
|
||||
// 1. get all event type's attribute types!
|
||||
// 2. get all attribute type's attribute texts! getAttributeText(..)
|
||||
|
||||
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); // key (derefd')!
|
||||
|
||||
// Do not allow filtering for INTERPRETER_TYPE_NONE (e.g. Marker)
|
||||
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); // create a combobox with all attributes for the given event type
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* provides user-management for events for a filter in filter table entry
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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 &); // no implementation
|
||||
|
||||
public:
|
||||
QComboBox *createAttributesComboBox(int eventType);
|
||||
|
||||
// >>>>>>> (EVENT_TYPE has (ATTRIBUTE_TYPE has (FilterData::ATTRIBUTE_UI_TYPE and POSSIBLE_VALUES)))
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
+334
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* entry to manage a specific filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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) // directly creates ftw with selected event type
|
||||
: QGroupBox(parent)
|
||||
, m_logger(getLogger("EventFilter.FilterTableEntry"))
|
||||
, m_eventType(eventType)
|
||||
|
||||
// ui
|
||||
, m_mainLayout(new QVBoxLayout())
|
||||
, m_topLayout(new QHBoxLayout())
|
||||
, m_centerLayout(new QHBoxLayout())
|
||||
, m_cbEventSelector(nullptr) // prepare cb
|
||||
, 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);
|
||||
|
||||
// soft init: only init cb & ok-button (mini-selection mode)
|
||||
|
||||
|
||||
setLayout(m_mainLayout);
|
||||
|
||||
|
||||
// top layout
|
||||
QWidget *topLayoutWidget = new QWidget(this);
|
||||
//topLayoutWidget->setStyleSheet("background-color:#97B0CC"); //#D6FFFF;"); // layer 1
|
||||
|
||||
topLayoutWidget->setLayout(m_topLayout);
|
||||
|
||||
m_mainLayout->addWidget(topLayoutWidget, 0, Qt::AlignTop); // add top widget with top alingment
|
||||
|
||||
|
||||
// start mini-selection mode
|
||||
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); // end selection mode => start editing mode
|
||||
|
||||
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(); // start making it a ready to use event filter for a specific event
|
||||
|
||||
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()); // try to convert to fte
|
||||
|
||||
if (!ftec) // not an 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
|
||||
{
|
||||
// get all attribute filters
|
||||
|
||||
if (m_eventType == -1/* || !m_filterActive*/)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "FilterTableEntry has no event type.";
|
||||
//warn("fte: fte has no event type (still in selection mode?)");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!m_centerLayout->count()) // if there are no children, do not worry, it should be possible to just filter by the event type
|
||||
{
|
||||
//info("fte: empty");
|
||||
}
|
||||
|
||||
|
||||
QJsonObject result;
|
||||
|
||||
QString eventTypeString;
|
||||
|
||||
if (typeSafe)
|
||||
eventTypeString = QString::number(m_eventType);
|
||||
else
|
||||
eventTypeString = m_detailData->eventTypeLookup.getEventText(m_eventType); // getEventTypeString(eventType);
|
||||
|
||||
if (!eventTypeString.length())
|
||||
return QJsonObject();
|
||||
|
||||
//info("fte: event type #" + QString::number(eventType) + " = " + eventTypeString);
|
||||
|
||||
|
||||
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()); // try to convert to fte
|
||||
|
||||
if (!ftec) // not an ftec
|
||||
{
|
||||
WARNING_LOG(m_logger) << "FilterTableEntry::filterText(): !ftec";
|
||||
continue;
|
||||
}
|
||||
|
||||
//info("fte: ftec found");
|
||||
|
||||
QJsonObject filterTile = ftec->filter(typeSafe); // the typeSafe parameter kills off the STR_COMPARE as we only safe ID's or ints, so do not implement it
|
||||
|
||||
if (filterTile.isEmpty()) // ftec has no result, continue!
|
||||
continue;
|
||||
|
||||
attributes.append(filterTile);
|
||||
}
|
||||
|
||||
result[QStringLiteral("Attributes")] = attributes;
|
||||
result[QStringLiteral("Active")] = m_pbFilterActive->isChecked();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotSelectEventType() // end selection mode => start editing mode
|
||||
{
|
||||
delete m_lbSelectText; // delete help text (not needed anymore)
|
||||
|
||||
// end selection mode
|
||||
if (m_cbEventSelector) // if there are no attribute filters yet..
|
||||
{
|
||||
if (m_eventType == -1) // do not reload if already set (set by constructor when set-function is used)
|
||||
{
|
||||
m_eventType = m_detailData->eventTypeLookup.getEventType(m_cbEventSelector->currentText()); // DOES NOT WORK ANYMORE: m_cbEventSelector->currentIndex();
|
||||
}
|
||||
|
||||
m_lbEventName = new QLabel(QString(tr("Filter by event type: <b>%1</b>")).arg(m_detailData->eventTypeLookup.getEventText(m_eventType))); //m_cbEventSelector->currentText()); // get event name
|
||||
m_lbEventName->setMinimumWidth(m_cbEventSelector->width()); // gets the optics straight! FIXME: width was never set
|
||||
|
||||
delete m_cbEventSelector; // event type is now fixed, replace cb with lb
|
||||
m_cbEventSelector = nullptr; // don't forget to set to 0 or this if-clause can't see that cb is already deleted => crash
|
||||
|
||||
m_topLayout->insertWidget(0, m_lbEventName); // add where the cb was
|
||||
}
|
||||
|
||||
if (m_eventType == -1)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "slotSelectEventType: m_eventType == -1";
|
||||
return;
|
||||
}
|
||||
|
||||
delete m_pbOK; // delete ok button
|
||||
|
||||
|
||||
|
||||
|
||||
// start editing mode
|
||||
|
||||
// horizontal line under add button
|
||||
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; // must be recreated because of the stretch at the end whil in selection mode
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
// do not add attributes if there are none
|
||||
DetailData::AttributeEventLookup::AttributeList attributeList = m_detailData->attributeEventLookup.getEventsAttributeList(m_eventType);
|
||||
|
||||
|
||||
// remove unfilterables:
|
||||
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);
|
||||
//pbAddFilter->setMinimumWidth(30);
|
||||
//pbAddFilter->setMaximumWidth(30);
|
||||
m_mainLayout->insertWidget(2, pbAddAttribute, 0, Qt::AlignLeft);
|
||||
}
|
||||
|
||||
|
||||
void FilterTableEntry::slotShowEvents()
|
||||
{
|
||||
QJsonArray a;
|
||||
a.append(filter(true /* type safe! */));
|
||||
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); // add all FTECs to the left
|
||||
|
||||
return ftec;
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* entry to manage a specific filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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 //QWidget
|
||||
{
|
||||
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;
|
||||
/**
|
||||
* @brief addFilter adds a filter to the filter table layout and returns the new pointer (for set-functionality)
|
||||
* @return new created ftw pointer
|
||||
*/
|
||||
FilterTableEntryAttribute *addAttribute(const QString &attributeType = QString());
|
||||
bool hasAttributes() const;
|
||||
void updateData();
|
||||
|
||||
|
||||
private:
|
||||
NGL::INGLLogger &m_logger;
|
||||
QComboBox *getEventTypesComboBox();
|
||||
|
||||
int m_eventType;
|
||||
|
||||
// ui
|
||||
QVBoxLayout *m_mainLayout{nullptr}; // for topLayout,
|
||||
QHBoxLayout *m_topLayout{nullptr}; // for event, delete, show events
|
||||
QHBoxLayout *m_centerLayout{nullptr}; // for many filtering types
|
||||
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); // provided by filter text (use filter, get all fitting events by setting SHOW/HIDE to false and returning only the list of affected events)
|
||||
void signalChanges();
|
||||
|
||||
private slots:
|
||||
void slotAddAttribute();
|
||||
void slotFilterActiveClicked();
|
||||
void slotSelectEventType();
|
||||
void slotShowEvents();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief slotSetFoundEventsCount sets the variable for how much events could be found with this filter (called by parent, holding this fte)
|
||||
* @param foundEvents count of events found with this filter
|
||||
*/
|
||||
|
||||
//void slotSetFoundEventsCount(int foundEvents);
|
||||
};
|
||||
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* attribute entry to manage a specific attribute
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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) // CAN be invalid
|
||||
, m_selectionModeUI(nullptr)
|
||||
, m_editionModeUI(nullptr)
|
||||
, m_attributesLayout(new QVBoxLayout())
|
||||
, m_detailData(detailData)
|
||||
, m_logger(getLogger("EventFilter.FilterTableEntryAttribute"))
|
||||
{
|
||||
//this->setStyleSheet("background-color:#436C99;"); // layer 2
|
||||
this->setTitle(QString());
|
||||
|
||||
setLayout(m_attributesLayout);
|
||||
|
||||
|
||||
/* Selection Mode Explanation:
|
||||
*
|
||||
* 1. Mode: Empty Mode DEPRECATED & DELETED!
|
||||
*
|
||||
* > Empty Widget
|
||||
* > PushButton "+" to end Empty Mode and goto Selection Mode
|
||||
* > goes onto 2. Mode
|
||||
*
|
||||
*
|
||||
* 2. Mode: Selection Mode
|
||||
*
|
||||
* > ComboBox with Event-specific types: (Munition, Players, etc.)
|
||||
* > PushButton "+" to END Selection Mode (turns ComboBox to QLabel, so that Event-specific Type is FIXED)
|
||||
*
|
||||
*
|
||||
* 3. Mode: Editing Mode
|
||||
*
|
||||
* > Useable Widget
|
||||
* > Label with chosen Event-specific Type
|
||||
* > ComboBox with Type-specific attributes: (adding Munition-Types if the Event-specific type was Munition)
|
||||
* >> (has to load Type-specific attributes relating to the selected Event-specific type! Munition -> Munition types)
|
||||
* > PushButton "+" to add another Type-specific attribute:
|
||||
* >> adds another ComboBox and PushButton for further adding more attributes
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
//setStyleSheet("FilterTableEntryAttribute { border: 1px solid black }");
|
||||
|
||||
slotAddSelectionMode();
|
||||
|
||||
if (!attributeType.isEmpty())
|
||||
{
|
||||
m_selectionModeUI->cbAttributeType->setCurrentIndex(m_selectionModeUI->cbAttributeType->findData(QVariant::fromValue<QString>(attributeType))); // set initial value by id
|
||||
slotAddEditingMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
FilterTableEntryAttribute::~FilterTableEntryAttribute()
|
||||
{
|
||||
delete m_editionModeUI; // not a widget, not parented
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::updateData(DetailData *detailData)
|
||||
{
|
||||
if (!m_editionModeUI)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++) // now get values for attribute value(s) list (from attribute layout, only available in editing mode)
|
||||
{
|
||||
AbstractAttributeWidget *aaw = /*qobject_cast*/dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
|
||||
|
||||
if (!aaw) // not a aaw derived class
|
||||
continue;
|
||||
|
||||
aaw->updateData(detailData);
|
||||
connect(aaw, &AbstractAttributeWidget::deleteClicked, this, [this]()
|
||||
{
|
||||
emit attributeChanged(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QJsonObject FilterTableEntryAttribute::filter(bool typeSafe) const // ftea alias "ftec"
|
||||
{
|
||||
if (m_attributeType.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "filterText: m_attributeType == -1";
|
||||
//warn("ftec: missing attribute type while getting filter text from attribute (still in selection mode?)");
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
|
||||
QString attributeTypeName;
|
||||
|
||||
if (typeSafe)
|
||||
attributeTypeName = m_attributeType;
|
||||
else
|
||||
{
|
||||
attributeTypeName = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType); //getAttributeTypeString(m_attributeType);
|
||||
}
|
||||
|
||||
if (attributeTypeName.isEmpty())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "filterText: !attributeTypeName.length()";
|
||||
//warn("ftec: missing attribute text while getting filter text from attribute");
|
||||
return QJsonObject();
|
||||
}
|
||||
|
||||
|
||||
QJsonObject result;
|
||||
result[QStringLiteral("AttributeType")] = attributeTypeName;
|
||||
|
||||
// translate all attributes + their value(s)
|
||||
// must be: * Attributes : [Attr Type]{[Attr Value],[Attr Value], ...}
|
||||
|
||||
|
||||
QJsonArray values;
|
||||
|
||||
if (m_editionModeUI)
|
||||
{
|
||||
for (int i = 0; i < m_editionModeUI->attributeValuesLayout->count(); i++) // now get values for attribute value(s) list (from attribute layout, only available in editing mode)
|
||||
{
|
||||
AbstractAttributeWidget *aaw = /*qobject_cast*/dynamic_cast<AbstractAttributeWidget *>(m_editionModeUI->attributeValuesLayout->itemAt(i)->widget());
|
||||
|
||||
if (!aaw) // not a aaw derived class
|
||||
continue;
|
||||
|
||||
//info("ftec: aaw derived class found");
|
||||
|
||||
QString value = aaw->filterText(typeSafe); // ishygddt without a derived class
|
||||
|
||||
if (value.isEmpty())
|
||||
continue;
|
||||
|
||||
values.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result[QStringLiteral("AttributeValues")] = values;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotAddSelectionMode()
|
||||
{
|
||||
// end Empty Mode
|
||||
/*if (!m_emptyModeUI)
|
||||
return;
|
||||
|
||||
delete m_emptyModeUI;
|
||||
m_emptyModeUI = 0;*/
|
||||
|
||||
// 2. Mode: Selection Mode
|
||||
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)
|
||||
{
|
||||
// end selection mode
|
||||
if (!m_selectionModeUI)
|
||||
return;
|
||||
|
||||
// 3. Mode: Editing Mode
|
||||
QString attributeTypeString;
|
||||
|
||||
if (m_attributeType.isEmpty()) // get text from combobox, when attribute type not given
|
||||
{
|
||||
attributeTypeString = m_selectionModeUI->cbAttributeType->currentText();
|
||||
m_attributeType = m_detailData->attributeTypeLookup.getAttributeType(attributeTypeString);
|
||||
}
|
||||
else // get text from filter data, when attribute type given by set-function
|
||||
{
|
||||
attributeTypeString = m_detailData->attributeTypeLookup.getAttributeText(m_attributeType);
|
||||
// do not set attribute type when it is already given!
|
||||
}
|
||||
|
||||
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); // munition
|
||||
|
||||
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);
|
||||
|
||||
// add first attribute container to events layout
|
||||
if (createBlankContainer)
|
||||
slotAddAttributeContainer();
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotDeleteAttributeContainer() // delete attribute (munition, player, etc.)
|
||||
{
|
||||
emit attributeChanged(false);
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void FilterTableEntryAttribute::slotAddAttributeContainer()
|
||||
{
|
||||
emit signalChanges();
|
||||
emit attributeChanged(true);
|
||||
if (m_editionModeUI != nullptr)
|
||||
m_editionModeUI->addAttributeContainer(m_eventType);
|
||||
}
|
||||
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* attribute entry to manage a specific attribute
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AttributeEditingModeUI.h"
|
||||
#include "AttributeSelectionModeUI.h"
|
||||
#include <QGroupBox>
|
||||
|
||||
class QLabel;
|
||||
class QVBoxLayout;
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class FilterTableEntryAttribute : public QGroupBox //QWidget
|
||||
{
|
||||
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;
|
||||
|
||||
// ui
|
||||
//EmptyModeUI* m_emptyModeUI;
|
||||
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(); // delete attribute (munition, player, etc.)
|
||||
void slotAddSelectionMode(); // to end Empty Mode
|
||||
void slotAddEditingMode(bool createBlankContainer = true); // to end Selection Mode
|
||||
};
|
||||
|
||||
}
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* table widget to manage filters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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_filterWorker(new FilterWorker(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);
|
||||
|
||||
// m_buttonBox->connectButton(LtsWidgets::DialogButton::Hide,
|
||||
// this, &FilterWindow::slotHide);
|
||||
|
||||
|
||||
// UPDATER
|
||||
connect(updateTimer, &QTimer::timeout, this, &FilterWindow::slotUpdate);
|
||||
updateTimer->setInterval(5000);
|
||||
updateTimer->start();
|
||||
|
||||
// // HACK: but works good for FAT
|
||||
// QTimer *hack = new QTimer(this);
|
||||
// hack->setInterval(750);
|
||||
// // NOTE: super difficult to track changes, so make apply always available
|
||||
// connect(hack, &QTimer::timeout, this, &FilterWindow::slotChangesMade);
|
||||
// hack->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()); // try to convert to fte
|
||||
|
||||
if (!fte) // not an fte (e.g. ignore add button)
|
||||
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->insertWidget(1, fte); // after the ADD button !
|
||||
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()); // try to convert to fte
|
||||
|
||||
if (!fte) // not an fte (e.g. ignore add button)
|
||||
continue;
|
||||
|
||||
const QJsonObject filterTile = fte->filter(true /* type safe !! */);
|
||||
if (filterTile.isEmpty()) // fte has no result, continue!
|
||||
continue;
|
||||
|
||||
result.append(filterTile);
|
||||
}
|
||||
|
||||
//filterTextEdit->setText(filterText);
|
||||
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()
|
||||
{
|
||||
//emit signalApplyFilter(QString());
|
||||
}
|
||||
|
||||
|
||||
void FilterWindow::slotApplyFilter()
|
||||
{
|
||||
emit signalApplyFilter(exportFilter());
|
||||
//emit signalChangesMade(); // => slotChangesMade(); // NOTE: super difficult to track changes, so make apply always available
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
// first ask if filters can be replaced by loaded ones
|
||||
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();
|
||||
|
||||
// call setUnchangeable(false) before the scope (whenever) of this fn endsq
|
||||
#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
|
||||
|
||||
|
||||
// get model filter lsit by filter text
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// now, after we know that the filter set is valid: first remove all old filters from Filter Set
|
||||
while (m_ui->filterContainer->count())
|
||||
{
|
||||
delete m_ui->filterContainer->itemAt(0)->widget(); // delete (removes them from the layout automatically)
|
||||
}
|
||||
|
||||
|
||||
const ModelFilterList &modelFilterList = result.result;
|
||||
|
||||
// now create all new filters and add to laoyut
|
||||
int lastEventType = -1;
|
||||
FilterTableEntry *lastFTW = nullptr;
|
||||
|
||||
QString lastAttributeType; // empty = events only
|
||||
FilterTableEntryAttribute *lastFTEA = nullptr;
|
||||
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList)
|
||||
{
|
||||
if (lastEventType != mf.eventType || lastEventType == -1 || !lastFTW) // create a new FTE when we are not the same event type anymore (or there never was a fte)
|
||||
{
|
||||
lastEventType = mf.eventType;
|
||||
lastFTW = addNewFilter(mf.eventType, mf.active); // create a new event filter
|
||||
}
|
||||
|
||||
if (mf.attributeType == QString()) // attribute type 0 = EVENT_ONLY (create event, but do not add attribute entry !
|
||||
continue;
|
||||
|
||||
if (lastAttributeType != mf.attributeType || lastAttributeType.isEmpty() || !lastFTEA)
|
||||
{
|
||||
lastAttributeType = mf.attributeType;
|
||||
lastFTEA = lastFTW->addAttribute(mf.attributeType); // create a new attribute filter
|
||||
}
|
||||
|
||||
EditingModeUI *emui = lastFTEA->m_editionModeUI;
|
||||
|
||||
if (!emui)
|
||||
continue;
|
||||
|
||||
emui->addAttributeContainer(mf.eventType, mf.attributeValue); // create a new attribute container witht he given value
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* table widget to manage filters
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#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); // invalid
|
||||
|
||||
//void addFilterToTable(const NGLDAO::EventFilter &eventFilter);
|
||||
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;
|
||||
//FilterWorker *m_filterWorker;
|
||||
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 &);
|
||||
//void signalFilterInTableChanged(const NGLDAO::EventFilter &); // redirection
|
||||
//void signalNewFilter(const NGLDAO::EventFilter &); // redirection
|
||||
|
||||
public slots:
|
||||
void slotLoad();
|
||||
void slotSave();
|
||||
void slotUpdate();
|
||||
void slotAddNewFilter();
|
||||
|
||||
private slots:
|
||||
void slotApplyFilter();
|
||||
void slotShowEvents();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
Executable
+309
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* equations methods for filter/interpreter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
// Detail Data Filter Text
|
||||
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);
|
||||
|
||||
|
||||
|
||||
/*/ Y
|
||||
* | N1
|
||||
* O1 |
|
||||
* ----------- X
|
||||
* | O2
|
||||
* N2 |
|
||||
/*/
|
||||
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
/*/ Y
|
||||
* | 'C' = center
|
||||
* = '=' = radius
|
||||
* ---==C==--- X
|
||||
* =
|
||||
* |
|
||||
/*/
|
||||
|
||||
|
||||
|
||||
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) // filter for 0 ?
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("FilterEquationFunctions"));
|
||||
(void)detailData;
|
||||
|
||||
bool ok1 = false;
|
||||
bool ok2 = false;
|
||||
|
||||
//qWarning() << "isIntEqual: val1 =" << value << " val2 =" << interpreterText;
|
||||
|
||||
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); // inTime is a range checker
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_AREA:
|
||||
{
|
||||
return inArea(detailData, value, interpreterText);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_RAD: // TODO: test !!
|
||||
{
|
||||
return inRad(detailData, value, interpreterText);
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_STR_COMPARE: // TODO: rm - unused
|
||||
{
|
||||
//WARNING_LOG(logger) << "INTERPRETER_TYPE_STR_COMPARE value " << value.toString() << " text " << interpreterText;
|
||||
|
||||
if (value.toString() == interpreterText) // ez
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_ID_COMPARE:
|
||||
{
|
||||
bool tryIt = isIntEqual(detailData, value, interpreterText);
|
||||
|
||||
// NOTE: everything typesafe, ids only
|
||||
// if (!tryIt) // means: cannot convert text OR is not equal; reason: is text OR is not equal; solution: probably value string - getIDKeyFromValue!!
|
||||
// {
|
||||
// int newTry = detailData->attributeValueLookup.getValueIDKeyFromValueString(attributeType, interpreterText);
|
||||
|
||||
// if (newTry == -1) // not even a value string (solution does not work)
|
||||
// {
|
||||
// DEBUG_LOG(logger) << "checkValue: no key found";
|
||||
// tryIt = false;
|
||||
// }
|
||||
// else // okay, seems to be a value string
|
||||
// {
|
||||
// tryIt = isIntEqual(detailData, value, QString::number(newTry));
|
||||
// }
|
||||
// }
|
||||
|
||||
return tryIt;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/* attribute types with ui type for combobox can redirect unproblematically
|
||||
* => attribute types with special ui type(s) should not be redirected
|
||||
* so if the attempt to lookup a attribute interpreter type fails, try another lookup with redirection
|
||||
* side effects can only happen if new attribute types are not completly integrated */
|
||||
|
||||
// TODO: endless loops possible in some way?
|
||||
|
||||
|
||||
// QString newAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
// //qWarning() << "checkValue: newAttributeType" << newAttributeType << " attributeType" << attributeType;
|
||||
|
||||
// if (newAttributeType != attributeType) // not equal = redirection
|
||||
// {
|
||||
// return checkValue(detailData, newAttributeType, value, interpreterText); // try again with redirected attribute type
|
||||
// }
|
||||
|
||||
//qWarning() << "checkValue: attribute type"<<attributeType<<"not handled";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool FilterEquationFunctions::checkValue(DetailData *detailData, const QString &attributeType, const QVariant &value, const QString &interpreterText)
|
||||
{
|
||||
int attributeInterpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType); // get interpretertype (e.g. for area_pos for pos)
|
||||
return checkValue(detailData, attributeInterpreterType, value, interpreterText);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* equations methods for filter/interpreter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter for filter in excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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) // must be 4 values (N1, N2, O1, O2)
|
||||
{
|
||||
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);
|
||||
|
||||
/*/ Y
|
||||
* | N1
|
||||
* O1 |
|
||||
* ----------- X
|
||||
* | O2
|
||||
* N2 |
|
||||
/*/
|
||||
|
||||
if (!ok1) // do not set coord if some value could nbot be converted
|
||||
{
|
||||
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); // add more informations like: INFO_INT_IS_NEGATIVE [if (result < 0)] if needed
|
||||
|
||||
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('-')); // 123456789-123456900 (why does ('-') not work ???)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: radius
|
||||
|
||||
case DetailData::INTERPRETER_TYPE_STR_COMPARE: // TODO: rm - unused
|
||||
{
|
||||
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); // -1 = invalid
|
||||
return interpretValue(detailData, interpreterType, value);
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter for filter in excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
class DetailData;
|
||||
|
||||
class InterpreterResult
|
||||
{
|
||||
public:
|
||||
enum class InterpreterResultTypes
|
||||
{
|
||||
RESULT_UNKNOWN,
|
||||
RESULT_SUCCESS,
|
||||
//RESULT_UNKNOWN_INTERPRETER_TYPE,
|
||||
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);
|
||||
|
||||
}
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter to convert text-filter to model filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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()
|
||||
{
|
||||
//qWarning() << "~FilterWorker";
|
||||
}
|
||||
|
||||
|
||||
void FilterWorker::deleteInstance()
|
||||
{
|
||||
// TODO: rm
|
||||
// if (s_instance)
|
||||
// {
|
||||
// delete s_instance;
|
||||
// s_instance = 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //qWarning() << "~FilterWorker [no instance to delete!]";
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
// WARNING: addErrorHandler auto discover paramCOunt: .find("%").count ! also, do not use single %'s more than once
|
||||
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::INFO_EVENT_ONLY_FILTER, tr("%1: Filtering by event type only"));
|
||||
//addErrorHandler(GetModelFilterListResult::INFO_NO_FILTERS, tr("No filters selected - now resetting Timeline Filters"));
|
||||
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'"));
|
||||
}
|
||||
|
||||
|
||||
/* PRIVATE */ 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;
|
||||
}
|
||||
|
||||
|
||||
/* PRIVATE */ 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) // returns a ResultStruct, as the user has to know WHAT failures he did when writing the filter text by himself!
|
||||
{
|
||||
GetModelFilterListResult result;
|
||||
|
||||
if (filter.isEmpty()) // no text, no filters
|
||||
{
|
||||
//result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::INFO_NO_FILTERS));
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto i1 = filter.constBegin(); i1 != filter.constEnd(); ++i1) // seperate Event Type from Rest & get attribute list per event type >>> "Shot" "Munition{...},Bla{...},..." <<<
|
||||
{
|
||||
const QJsonObject ¤tFilter = (*i1).toObject();
|
||||
|
||||
//#warning TODO: used?
|
||||
// if (currentFilter.isEmpty())
|
||||
// {
|
||||
// result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_NO_EVENT_NAME,
|
||||
// QString::number(i1)));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (currentFilter[QStringLiteral("Active")].toBool(false))
|
||||
// continue;
|
||||
|
||||
QString eventTypeString = currentFilter[QStringLiteral("EventType")].toString(); // get event type string & look if event type string exists & get attribute keys for event type 0 = Event Type
|
||||
int eventType = -1;
|
||||
|
||||
if (fromTypeSafe)
|
||||
{
|
||||
bool ok = false;
|
||||
eventType = eventTypeString.toInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
eventType = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eventType = detailData->eventTypeLookup.getEventType(eventTypeString); // get event type by its string fromt he lookup list
|
||||
}
|
||||
|
||||
|
||||
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()) // if there are NO attributes, then add this a event-only-filter
|
||||
{
|
||||
ModelFilter mf; // already done!
|
||||
mf.eventType = eventType;
|
||||
mf.attributeType = QString(); // aka 'ATTRIBUTE_TYPE_EVENT_ONLY'
|
||||
mf.active = active;
|
||||
//mf.attributeValue = 0; QString is invalid when created
|
||||
result.result.append(mf);
|
||||
|
||||
continue; // next!
|
||||
}
|
||||
|
||||
// otherwise.. is/are attribute(s) then must have one Event Type and the Attributes (as one)
|
||||
|
||||
for (auto i2 = attributes.constBegin(); i2 != attributes.constEnd(); i2++) // process every value for that attribute
|
||||
{
|
||||
const QJsonObject &attribute = (*i2).toObject();
|
||||
QString attributeType = attribute[QStringLiteral("AttributeType")].toString(); // type => "GearType"
|
||||
|
||||
if (!fromTypeSafe)
|
||||
{
|
||||
attributeType = detailData->attributeTypeLookup.getAttributeType(attributeType); // get attribute type by attribute type string
|
||||
}
|
||||
|
||||
|
||||
// NOTE: fix this in ngldao timeline, too
|
||||
attributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
|
||||
if (attributeType.isEmpty()) // no attribute type found from attribute type string? next!
|
||||
{
|
||||
result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_UNKNOWN_ATTRIBUTE_TYPE_BY_STRING,
|
||||
attributeType));
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: fix this in ngldao timeline
|
||||
|
||||
// TODO: FIXME: we must trust that the attribute type is in the event *for now*. Because there is no backwards-lookup from *redirected* attributes back to the original !
|
||||
|
||||
|
||||
// if (!detailData->attributeEventLookup.isAttributeInEvent(eventType, attributeType)) // check if event has that attribute
|
||||
// {
|
||||
// QStringList vl;
|
||||
// vl.append(attributeTypeString);
|
||||
// vl.append(eventTypeString);
|
||||
// vl.append(currentFilterString);
|
||||
|
||||
// result.resultValueList.append(makeResult(GetModelFilterListResult::ResultValues::ERR_EVENT_HAS_NOT_ATTRIBUTE,
|
||||
// vl));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
|
||||
// check if this is an pure string
|
||||
int interpreterType = detailData->attributeInterpreterLookup.getInterpreterType(attributeType);
|
||||
|
||||
if (interpreterType == DetailData::INTERPRETER_TYPE_NONE)
|
||||
{
|
||||
continue; // ignore, not filterable
|
||||
}
|
||||
|
||||
|
||||
const QJsonArray &attributeValues = attribute[QStringLiteral("AttributeValues")].toArray(); // values => "M3,M5, ..."
|
||||
for (auto i3 = attributeValues.constBegin(); i3 != attributeValues.constEnd(); ++i3)
|
||||
{
|
||||
QString attributeValueString = (*i3).toString(); // get single value >>> "M3" <<<
|
||||
|
||||
// remember: attribute value id is -2 for attribute types without entries in attribute value lookup <<<< Ist das noch so?
|
||||
|
||||
ModelFilter mf; // create a model filter for every value
|
||||
mf.eventType = eventType;
|
||||
mf.attributeType = attributeType;
|
||||
mf.active = active;
|
||||
mf.attributeValue = attributeValueString;
|
||||
result.result.append(mf);
|
||||
|
||||
// qWarning() << "new model filter: event type " << eventType << " attr type " << attributeType << " attr val " << attributeValueString << " active " << mf.active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) // check if ERROR-bit is set (when there are no errors yet)
|
||||
{
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
if (ignoreInfos && (resultValue & GetModelFilterListResult::INFO) == GetModelFilterListResult::INFO)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// lookup error handler
|
||||
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; // cannot handle, handle next info
|
||||
}
|
||||
|
||||
|
||||
// add info to text
|
||||
int additionalInformationCount = result.additionalInformation.count();
|
||||
QString iweText = eh.errorText;
|
||||
|
||||
if (eh.errorParamCount) // only fill text if there is some text to fill with
|
||||
{
|
||||
for (int i2 = 0; i2 < eh.errorParamCount; i2++) // add every REQUESTED parameter by getting the value from the list (check if count is hogh enough, otherwise parameter will be '???')
|
||||
{
|
||||
if (additionalInformationCount >= eh.errorParamCount) // only add from addInfo list if the requested error param iterator < add info count !
|
||||
{
|
||||
iweText = iweText.arg(result.additionalInformation.at(i2));
|
||||
}
|
||||
else // add info is missing, fill with '???'
|
||||
{
|
||||
iweText = iweText.arg(QStringLiteral("???"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iwe.text = iweText;
|
||||
iwel.append(iwe);
|
||||
}
|
||||
|
||||
|
||||
if (iwel.count())
|
||||
{
|
||||
InfoWindow* iw = new InfoWindow(iwel, parentWidget);
|
||||
iw->show();
|
||||
}
|
||||
|
||||
return !errorOccured; // must return true if NO errors occured
|
||||
}
|
||||
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* interpreter to convert text-filter to model filter
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#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(); // TODO: to qt instance
|
||||
|
||||
// static Q_CONSTEXPR QLatin1Char filterSeparator() { return QLatin1Char(';'); }
|
||||
// static Q_CONSTEXPR QLatin1Char filterEventNamespace() { return QLatin1Char(':'); }
|
||||
// static Q_CONSTEXPR QLatin1Char attributeSeparator() { return QLatin1Char('+'); }
|
||||
// static Q_CONSTEXPR QLatin1Char attributeValueSeparator() { return QLatin1Char(','); }
|
||||
// static Q_CONSTEXPR QLatin1Char bracketOpen() { return QLatin1Char('{'); }
|
||||
// static Q_CONSTEXPR QLatin1Char bracketClose() { return QLatin1Char('}'); }
|
||||
|
||||
struct ModelFilter
|
||||
{
|
||||
int eventType = -1;
|
||||
QString attributeType;
|
||||
bool active = false;
|
||||
QString attributeValue; // stores IDs or values (position ("xxxx.xxx;xxxx.xxx"), doubles, etc.)
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
int resultValue = -1;
|
||||
QStringList additionalInformation;
|
||||
};
|
||||
|
||||
struct GetModelFilterListResult
|
||||
{
|
||||
// 4 Bit ResultType => [0000] [0000] <= 4 Bit ResultValues
|
||||
|
||||
enum ResultType
|
||||
{
|
||||
ERR = 0x80, // bit 8 set - 1000 0000
|
||||
WARN = 0x40, // bit 7 set - 0100 0000
|
||||
INFO = 0x20, // bit 6 set - 0010 0000
|
||||
};
|
||||
|
||||
enum ResultValues
|
||||
{
|
||||
//INFO_NO_FILTERS = INFO | 0,
|
||||
//INFO_EVENT_ONLY_FILTER = INFO | 1,
|
||||
|
||||
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_UNKNOWN_ATTRIBUTE_TYPE_BY_TYPE = ERR | 6,
|
||||
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); // returns a ResultStruct, as the user has to know WHAT failures he did when writing the filter text by himself!
|
||||
bool handleResultValues(const QVector<Result> &resultList, QWidget* parentWidget = nullptr, bool ignoreInfos = false); // returns true if NO error(s) occured (info & warnings are okay) - false = ERRORS !!!
|
||||
|
||||
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>;
|
||||
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* window to provide errors and informations when applying filter to excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "InfoWindow.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
InfoWindow::InfoWindow(const InfoWindowEntryList &infoWindowEntryList, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, infoWindowEntryList(infoWindowEntryList)
|
||||
|
||||
|
||||
// ui
|
||||
, 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) // invalid / not positioned
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
// top buttons (< & >)
|
||||
QHBoxLayout* topButtonsLayout = new QHBoxLayout();
|
||||
pbPrev->setEnabled(false); // set prev disabled by default (as there is no prev)
|
||||
topButtonsLayout->addWidget(pbPrev);
|
||||
topButtonsLayout->addWidget(lbIndicator);
|
||||
topButtonsLayout->addWidget(pbNext);
|
||||
pbNext->setEnabled(false); // set next disabled by default (as there CAN be no next)
|
||||
QWidget* topButtonsWidget = new QWidget();
|
||||
topButtonsWidget->setLayout(topButtonsLayout);
|
||||
mainLayout->addWidget(topButtonsWidget);
|
||||
|
||||
|
||||
// text field for info / error / warning text
|
||||
mainLayout->addWidget(teText);
|
||||
|
||||
|
||||
// bottom buttons (ignore, ignore all, cancel)
|
||||
QHBoxLayout* bottomButtonsLayout = new QHBoxLayout();
|
||||
bottomButtonsLayout->addWidget(pbOK);
|
||||
QWidget* bottomButtonsWidget = new QWidget();
|
||||
bottomButtonsWidget->setLayout(bottomButtonsLayout);
|
||||
mainLayout->addWidget(bottomButtonsWidget);
|
||||
|
||||
|
||||
// fill first thingy....
|
||||
slotNext();
|
||||
|
||||
this->setLayout(mainLayout);
|
||||
}
|
||||
|
||||
void InfoWindow::checkNavigationButtons(int newPosition)
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
|
||||
if (newPosition -1 >= 0) // if there is no prev, do not show prev
|
||||
{
|
||||
pbPrev->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
pbPrev->setEnabled(false);
|
||||
}
|
||||
|
||||
if (newPosition +2 > listCount) // if there is no next, do not show next
|
||||
{
|
||||
pbNext->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pbNext->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoWindow::slotPrev()
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
int prevListPosition = listPosition - 1 /* 0 -1 = -1 */;
|
||||
|
||||
checkNavigationButtons(prevListPosition);
|
||||
|
||||
if (prevListPosition >= 0 && prevListPosition < listCount) // if there is a prev one
|
||||
{
|
||||
teText->setText(infoWindowEntryList.at(prevListPosition).text); // set text
|
||||
|
||||
QString indicatorString = QStringLiteral("%1/%2");
|
||||
lbIndicator->setText(indicatorString.arg(prevListPosition + 1 /* so there is no "Info 0" */).arg(listCount)); // set indicator like: "Info 4/8"
|
||||
|
||||
listPosition = prevListPosition; // set new current list position
|
||||
}
|
||||
}
|
||||
|
||||
void InfoWindow::slotNext()
|
||||
{
|
||||
int listCount = infoWindowEntryList.count();
|
||||
int nextListPosition = listPosition + 1 /* -1 + 1 = 0 */;
|
||||
|
||||
checkNavigationButtons(nextListPosition);
|
||||
|
||||
if (nextListPosition >= 0 && nextListPosition < listCount) // if there is a next one (some safety checks)
|
||||
{
|
||||
teText->setText(infoWindowEntryList.at(nextListPosition).text); // set text
|
||||
|
||||
QString indicatorString = QStringLiteral("%1/%2");
|
||||
lbIndicator->setText(indicatorString.arg(nextListPosition + 1 /* so there is no "Info 0" */).arg(listCount)); // set indicator like: "Info 4/8"
|
||||
|
||||
listPosition = nextListPosition; // set new current list position
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* window to provide errors and informations when applying filter to excon model
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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; // error, info, warning
|
||||
};
|
||||
|
||||
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; // current position in list which information is currently shown
|
||||
|
||||
void checkNavigationButtons(int newPosition);
|
||||
|
||||
|
||||
public slots:
|
||||
void slotPrev();
|
||||
void slotNext();
|
||||
};
|
||||
|
||||
}
|
||||
+1357
File diff suppressed because it is too large.
Load diff
+81
@@ -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>
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* abstract widget with basic/easy implementation of new widget types in Filter Table
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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()
|
||||
{
|
||||
//delete this; // deletes itself from the parents layout. DONE! <= UGH! Ich als Azubi halt :)
|
||||
emit deleteClicked();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void AbstractAttributeWidget::addCustomWidget(QWidget* widget)
|
||||
{
|
||||
m_abstractMainLayout->insertWidget(0, widget, 1, Qt::AlignLeft); // add widget to the left
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* abstract widget with basic/easy implementation of new widget types in Filter Table
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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; // only returns the chosen values for this attribute
|
||||
virtual void updateData(DetailData *detailData) = 0;
|
||||
|
||||
protected:
|
||||
void addCustomWidget(QWidget* widget); // use this method to add the abstracted widget to this base classes ready layout
|
||||
protected:
|
||||
QHBoxLayout *m_abstractMainLayout;
|
||||
|
||||
private slots:
|
||||
void slotDelete();
|
||||
|
||||
signals:
|
||||
void signalChanges();
|
||||
void deleteClicked();
|
||||
};
|
||||
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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); // top center
|
||||
mainLayout->addWidget(sbN2, 2, 1); // bottom center
|
||||
mainLayout->addWidget(sbO1, 1, 0); // left center
|
||||
mainLayout->addWidget(sbO2, 1, 2); // right center
|
||||
|
||||
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)
|
||||
{
|
||||
// data cannot change
|
||||
Q_UNUSED(detailData);
|
||||
}
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class AreaWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select true / false
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#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 *)
|
||||
{
|
||||
// data cannot change
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select true / false
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
#include "../../detail_data.h"
|
||||
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class CheckBoxWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select pre-defined value
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#include "ComboBox.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <QComboBox>
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
// combobox must be aware of getting his own data, as he needs to update himself (performance and coding reasons)
|
||||
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); // returns 'attributeType' if there is no redirection
|
||||
|
||||
updateData(detailData);
|
||||
|
||||
if (initialValue.isEmpty())
|
||||
return;
|
||||
|
||||
bool k = false;
|
||||
int initialValueKey = initialValue.toInt(&k);// everything is typesafe now, saved as index keys, not values which index have to be looked up anymore
|
||||
|
||||
if (initialValueKey < 0 || !k) // invalid!
|
||||
{
|
||||
WARNING_LOG(m_logger) << "ComboBox::c_tor: initialValueKey < 0 (" << initialValueKey << ")" << "initialValue: " << initialValue;
|
||||
return;
|
||||
}
|
||||
|
||||
// select initial value
|
||||
m_cbValues->setCurrentIndex(m_cbValues->findData(initialValueKey, Qt::UserRole)); // set initial value by id WARNING: does not check for invalid index
|
||||
}
|
||||
|
||||
|
||||
void ComboBox::updateData(DetailData *detailData)
|
||||
{
|
||||
int lastSelectedKey = -1;
|
||||
|
||||
if (m_cbValues->currentIndex() > 0) // none selected yet (if m_cbValues has to be built first)
|
||||
lastSelectedKey = m_cbValues->itemData(m_cbValues->currentIndex()).toInt();
|
||||
|
||||
// now reset and load new data
|
||||
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); // get new avm
|
||||
|
||||
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()); // add value and key (storing key as userdata)
|
||||
}
|
||||
|
||||
if (lastSelectedKey < 0) // only set new index if there was a last selected index first
|
||||
{
|
||||
m_cbValues->setCurrentIndex(0); // set to the first entry
|
||||
return; // done!
|
||||
}
|
||||
|
||||
// select old value (if one)
|
||||
m_cbValues->setCurrentIndex(m_cbValues->findData(lastSelectedKey, Qt::UserRole)); // set initial value by id WARNING: does not check for invalid index
|
||||
|
||||
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); // returns the selected value's ID
|
||||
else
|
||||
resultFilterText = m_avm.value(key); // returns the selected value's STRING
|
||||
|
||||
|
||||
return resultFilterText;
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select pre-defined value
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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); // combobox fills itself with values, by getting informations from FilterData
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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(); // focus first widget
|
||||
|
||||
|
||||
// not necessary, as initialValues are already checked bz checkValue ...
|
||||
if (initialValue.length()) // is there an initial value ?
|
||||
{
|
||||
QStringList valueList = initialValue.split(QLatin1Char('-'), QString::SkipEmptyParts);
|
||||
|
||||
if (valueList.count() != 2) // must be exactly 2 (e.g. "99,999")
|
||||
{
|
||||
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)
|
||||
{
|
||||
// not needed, as min / max is always static (0 - 999 bullets, etc)
|
||||
Q_UNUSED(detailData);
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select area with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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); // not ready to use!
|
||||
|
||||
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); // left
|
||||
mainLayout->addWidget(sbR, 0, 1); // middle
|
||||
mainLayout->addWidget(sbO, 0, 2); // right
|
||||
|
||||
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 *)
|
||||
{
|
||||
// TODO: !
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select radius with n1, n2, o1, o2
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AbstractAttributeWidget.h"
|
||||
|
||||
class QSpinBox;
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
class RadiusWidget : public AbstractAttributeWidget//QWidget
|
||||
{
|
||||
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; // radius
|
||||
};
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between time
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
// m_edit1->setCalendarPopup(true);
|
||||
// m_edit2->setCalendarPopup(true);
|
||||
|
||||
// m_edit1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
|
||||
// m_edit2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
|
||||
|
||||
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(); // focus first widget
|
||||
|
||||
|
||||
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 /* otherwise would not fit into int */); // secs since epoch
|
||||
filterText += QLatin1Char('-'); // trennzeichen
|
||||
filterText += QString::number(m_edit2->msecsSinceEpoch() / 1000 /* otherwise would not fit into int */); // s.a.a.
|
||||
|
||||
return filterText;
|
||||
}
|
||||
|
||||
|
||||
void TimeRangeWidget::updateData(DetailData *detailData)
|
||||
{
|
||||
LtsSession::LtsSession *session = detailData->session();
|
||||
m_edit1->setMsecsSinceEpoch(session->partitionTime() - 60 * 1000 /* TODO: minus 1 minute offset ? */);
|
||||
m_edit2->setMsecsSinceEpoch(session->partitionTime());
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* select any range between time
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2015-09-23
|
||||
*/
|
||||
|
||||
#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,303 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper classes to retrieve attribute values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Christian Ehrlicher, NLE, 2020-02-07
|
||||
*/
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
//
|
||||
// AvmChargeType
|
||||
//
|
||||
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);
|
||||
//charges =+ dtc->chargesForGearClass(GearClass::MineSingle); // same charges
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// AvmGearType
|
||||
//
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// AvmParty
|
||||
//
|
||||
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());
|
||||
}
|
||||
|
||||
//
|
||||
// AvmEquipmentNumber
|
||||
//
|
||||
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();
|
||||
}
|
||||
|
||||
//
|
||||
// AvmOperator
|
||||
//
|
||||
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());
|
||||
}
|
||||
|
||||
//
|
||||
// AvmBuilding
|
||||
//
|
||||
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::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());
|
||||
}
|
||||
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Helper classes to retrieve attribute values
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Christian Ehrlicher, NLE, 2020-02-07
|
||||
*/
|
||||
#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;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,928 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Model to handle datail data for the different event types
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-09-04
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
// Dtc lookups: (data ifc libs)
|
||||
#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>
|
||||
|
||||
|
||||
// Enums only: (svc libs only)
|
||||
#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)
|
||||
{
|
||||
// no QString::erase(it) available...
|
||||
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) // with default attribute types [time, etc.]
|
||||
{
|
||||
eventTypeLookup.addEventType(eventTypeId, eventTypeString);
|
||||
attributeEventLookup.addAttributesToEvent(eventTypeId, {QStringLiteral("TimeRange")});
|
||||
}
|
||||
|
||||
|
||||
void DetailData::addEventType(const ProjectDataManagement::EventType &eventType) // with default attribute types [time, etc.]
|
||||
{
|
||||
addEventType(eventType.underlying(), ProjectDataManagement::toString(eventType));
|
||||
}
|
||||
|
||||
|
||||
void DetailData::populate() // call on any retranslate
|
||||
{
|
||||
if (__already_populated__) // TODO: repopulate!!
|
||||
return;
|
||||
__already_populated__ = true;
|
||||
|
||||
|
||||
|
||||
// TODO: clear all lookups !
|
||||
|
||||
// populate Event Types - see build/Lts/Services/ExerciseEventManagement/eem_enums.hpp
|
||||
// * retrieved as of 2017-09-01
|
||||
|
||||
addEventType(0, tr("General")); // would be type 'unknown' in EventType_def DE: "Allgemein"
|
||||
|
||||
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("OriginatorId"), // TODO: kann ich nix mit anfangen..
|
||||
//QStringLiteral("OriginatorType"), // not really useful - see EEM HandlerDynamicParticipantData::tryCreateHitEvent()
|
||||
QStringLiteral("OriginatorEquipmentNumber")});
|
||||
break;
|
||||
case EventType::BiteMessage:
|
||||
break;
|
||||
case EventType::WeaponAssignment:
|
||||
case EventType::FireEvent:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {//<< QStringLiteral("GearId"), // is a unique serial number not known to excon operator
|
||||
QStringLiteral("GearTypeId"),
|
||||
QStringLiteral("ChargeTypeId")});
|
||||
break;
|
||||
case EventType::HitBuilding:
|
||||
attributeEventLookup.addAttributesToEvent(eventType, {QStringLiteral("AesType"),
|
||||
QStringLiteral("ChargeTypeId"),
|
||||
QStringLiteral("OriginatorEquipmentNumber"),
|
||||
QStringLiteral("MainStructureElementId"),
|
||||
QStringLiteral("VulnerabilityState"),
|
||||
QStringLiteral("damagePercent"), // range
|
||||
//QStringLiteral("damagePercentOld"),
|
||||
}); // range
|
||||
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);
|
||||
}
|
||||
|
||||
// populate Attribute Types - see /home/ref/TDS/src/Lts/Services/ExerciseEventManagement/eem_service.xml:52
|
||||
/*
|
||||
* retrieved as of 2017-09-04
|
||||
*
|
||||
*
|
||||
* FireEvent:
|
||||
* GearId
|
||||
* GearTypeId
|
||||
* ChargeTypeId
|
||||
* Remain
|
||||
*
|
||||
* WeaponAssignment:
|
||||
* GearId
|
||||
* GearTypeId
|
||||
* DryFire
|
||||
*
|
||||
* Manipulation: => show bite window
|
||||
* DeviceType
|
||||
* BiteMessage
|
||||
* BatteryState
|
||||
* BiteState
|
||||
* ConfigState
|
||||
* JsonArray BiteErrors:
|
||||
* ErrorNo
|
||||
* CanDeviceNumber
|
||||
* SubDeviceNumber
|
||||
* UniqueId
|
||||
*
|
||||
* HitBuilding:
|
||||
* ChargetTypeId
|
||||
* damagePercent
|
||||
* damagePercentOld
|
||||
* AesId
|
||||
* VunerabilityState
|
||||
* OriginatorParticipantId
|
||||
* MainStructureElementId
|
||||
*
|
||||
*
|
||||
* >>> Ab hier bin ich mir nicht mehr Sicher, was genau im Comment gemeint ist...
|
||||
* HitIndrect:
|
||||
* HitMine:
|
||||
* HitN:
|
||||
* HitC:
|
||||
* EnterDangerArea:
|
||||
* LeaveDangerArea:
|
||||
* CES:
|
||||
* AesId
|
||||
* FriendlyFire
|
||||
*/
|
||||
|
||||
/* Jedes Attribute benoetigt einen Interpreter Typen. Ein Interpreter Typ sagt dem Interpreter, wie er den Wert eines Attributs auf den Filter anwenden kann. Hier als Beispiel:
|
||||
* "OriginatorChargeTypeId" ist ein Attribut, welches bloß eine Value ID zurueckgibt. D.h. id:9000 (wird dann später einem lesbaren Wert zugeordnet: z.B: "30mm Irgendwas")
|
||||
* SOll der Wert im Filter also verglichen werden, muessen hier die IDs verglichen werden. Id 9000 => Id 9000.
|
||||
* Hier ist also folgender Interpreter korrekt: INTERPRETER_TYPE_ID_COMPARE
|
||||
*
|
||||
* Anderes Beispiel:
|
||||
* Zeit. Wird als Filter eine Zeit zwischen X und Y angegeben, muss geschaut werden, ob die Zeit Z sich zwischen X und Y befindet. Mit "INTERPRETER_TYPE_ID_COMPARE" wuerde das
|
||||
* nicht funktionieren, da sonst nur EINE Zeit (naemlich genau Zeitpunkt Z) beim Interpreter korrekt ist. Fuer diesen Fall gibt es "INTERPRETER_TYPE_RANGE".
|
||||
* Dieser Interpreter prueft, ob etwas in der Range zwischen X und Y ist.
|
||||
*/
|
||||
|
||||
// AttributeUiTypeLookup: Wie wird das Attribut angezeigt? Bei einer Liste aus Einträgen: COmboBox, oder wenn z.B. es nur 2 Zustände gib: FriendlyFire => Yes / No => CheckBox
|
||||
|
||||
addAttributeType(QStringLiteral("TimeRange"), tr("Time range:"), ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET /* TODO: none! */, INTERPRETER_TYPE_TIME); // is added in getDetailData as dummy so that the filter has a value to filter with TimeRange
|
||||
|
||||
|
||||
// Vulnerability State:
|
||||
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);
|
||||
//addAttributeValue(QStringLiteral("VulnerabilityState"), ProjectDataManagement::VulnerabilityState::NotReady);
|
||||
|
||||
|
||||
// Marker Types:
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsSituationType"), tr("Is situation type:"));
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsVideoType"), tr("Is video type:"));
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("IsAudioType"), tr("Is audio type:"));
|
||||
|
||||
|
||||
// AES Types:
|
||||
// addRedirectedAttributeType(QStringLiteral("AesId"), tr("Aes Type:"), QStringLiteral("AesType")); // because the result type is Aes Type (but has to be resolved by looking at the AES behind the AesId
|
||||
addAttributeType(QStringLiteral("AesType"), tr("Aes Type:"));
|
||||
|
||||
//addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtUnknown);
|
||||
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::AtTechnicalArea);
|
||||
//addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtExplosionAreaSingleExplosions);
|
||||
addAttributeValue(QStringLiteral("AesType"), AreaEffectSimulation::AesType::AtMineAreaSingleMines);
|
||||
|
||||
|
||||
// Friendly Fire
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("FriendlyFire"), tr("Friendly Fire:"));
|
||||
|
||||
// Attribute: Dry Fire
|
||||
addAttributeTypeWithYesAndNo(QStringLiteral("DryFire"), tr("Dry Fire:"));
|
||||
|
||||
|
||||
|
||||
|
||||
// non-filterables:
|
||||
addAttributeType(QStringLiteral("MarkerName"), tr("Name:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE);
|
||||
addAttributeType(QStringLiteral("MarkerNote"), tr("Note:"), ATTRIBUTE_UI_TYPE_CHECKBOX /* TODO: FIXME: none! */, INTERPRETER_TYPE_NONE);
|
||||
|
||||
|
||||
// TODO:
|
||||
//(QStringLiteral("Remain"), tr("Remain:")); was ist "remain" ?
|
||||
|
||||
|
||||
// Marker offset:
|
||||
addAttributeType(QStringLiteral("MarkerOffset"), tr("Offset [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, 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);
|
||||
}
|
||||
|
||||
|
||||
// Duration:
|
||||
addAttributeType(QStringLiteral("duration"), tr("Duration [msecs]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - x */, 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);
|
||||
}
|
||||
|
||||
|
||||
// Damage:
|
||||
addAttributeType(QStringLiteral("damagePercent"), tr("Damage [%]:"), ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET /* 0 - 100 */, 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); // only for filters (event filter), so only filtereable attributes like MUNITION_LEFT_BETWEEN (not MUNITION_LEFT!)
|
||||
}
|
||||
|
||||
// Equipment Numbers: (Achtung! Uebersetzt nur direkt eqid zu eqid !)
|
||||
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);
|
||||
// Charge Types:
|
||||
addAttributeType(QStringLiteral("ChargeTypeId"), tr("Charge Type:")); // Achtung: OriginatorChargeTypeId wird auf den Generellen Typ "ChargeTypeId" weitergeleitet, daher muss nur der Interpreter Type des Haupt-Typen gesetzt werden!
|
||||
addRedirectedAttributeType(QStringLiteral("OriginatorChargeTypeId"), tr("Originator Charge Type:"), QStringLiteral("ChargeTypeId"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("ChargeTypeId"), new AvmChargeType(dtcPdm));
|
||||
|
||||
// Gear Types:
|
||||
addAttributeType(QStringLiteral("GearTypeId"), tr("Gear Type:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("GearTypeId"), new AvmGearType(dtcPdm));
|
||||
|
||||
// Originator Types:
|
||||
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::WoundTreatmentDevice);
|
||||
//addAttributeValue(QStringLiteral("OriginatorType"), ProjectDataManagement::StateChangeOriginator::MaintainanceDevice);
|
||||
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);
|
||||
|
||||
|
||||
// (ISM) Structure Elements:
|
||||
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));
|
||||
|
||||
// (PPM) Parties
|
||||
addAttributeType(QStringLiteral("PartyId"), tr("Party:"));
|
||||
m_attributeValueLookupDtc.addHandlerForDtc(QStringLiteral("PartyId"), new AvmParty(dtcPpm));
|
||||
|
||||
// (OPM) Operator Management:
|
||||
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));
|
||||
|
||||
|
||||
// (AVM) Streams
|
||||
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()) // no detail data so search in
|
||||
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 /* as value would be too big for int => see getDetailDataForAttribute(..) */; // event time as temporary detail data
|
||||
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;
|
||||
//ERROR_LOG(m_logger) << "getDetailDataForAttribute: Invalid Attribute Type for " << attributeType;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.attributeType = attributeTypeTranslated;
|
||||
|
||||
int attributeValueId = -1;
|
||||
|
||||
/*
|
||||
enum Type
|
||||
{
|
||||
Null = 0x0,
|
||||
Bool = 0x1,
|
||||
Double = 0x2,
|
||||
String = 0x3,
|
||||
Array = 0x4,
|
||||
Object = 0x5,
|
||||
Undefined = 0x80
|
||||
};
|
||||
*/
|
||||
|
||||
switch (attributeValueJson.type())
|
||||
{
|
||||
// sorted by frequency of occurrence
|
||||
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) // not a number but treat as text... NOTE: has no id
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
// there are values that do not have to be translated:
|
||||
int attributeUiType = attributeUITypeLookup.getUIType(attributeType);
|
||||
switch (attributeUiType)
|
||||
{
|
||||
// do not translate
|
||||
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); // use "id" as "translated" string
|
||||
result.requestResult = DetailData::RequestResult::Okay;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// translate
|
||||
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: // -1
|
||||
{
|
||||
// maybe the type was redirected?
|
||||
QString concreteAttributeType = attributeRedirectionLookup.getRedirection(attributeType);
|
||||
|
||||
if (concreteAttributeType == attributeType) // it was not redirected - give up!
|
||||
{
|
||||
ERROR_LOG(m_logger) << "getDetailDataForAttribute: attribute type " << attributeType << " does not have an UiType !!!";
|
||||
result.requestResult = DetailData::RequestResult::NoUiTypeForAttribute;
|
||||
}
|
||||
else // there is a redirection, try this method with the redirection
|
||||
{
|
||||
//qWarning() << "trying redirection for attribute type" << attributeType;
|
||||
|
||||
// save some results, as getDetailDataForAttribute will set ALL the results for the redirection, instead of ONLY the value..
|
||||
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(); });
|
||||
}
|
||||
|
||||
|
||||
// LOOKUP BASE
|
||||
DetailData::LookupBase::LookupBase(const QString &lookupClassName)
|
||||
: m_lookupClassName(lookupClassName)
|
||||
, m_logger(getLogger(QStringLiteral("DetailData.") + lookupClassName))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// EVENT TYPE LOOKUP
|
||||
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
|
||||
{
|
||||
// as eventText is simplified, method 'key' would not work
|
||||
|
||||
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; // -1 = invalid !
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE EVENT LOOKUP
|
||||
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; // event does not even exist
|
||||
|
||||
const AttributeList &attributeList = *eventTypeIt;
|
||||
|
||||
if (attributeList.contains(attributeType))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DetailData::AttributeEventLookup::AttributeList DetailData::AttributeEventLookup::getEventsAttributeList(const int eventType) const // get all attribute types from the event
|
||||
{
|
||||
return m_attributeEventLookupMap.value(eventType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE TEXT LOOKUP
|
||||
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);
|
||||
// as eventText is simplified, method 'key' would not work
|
||||
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(); // invalid
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
// ATTRIBUTE PARAMETER LOOKUP
|
||||
DetailData::AttributeParameterLookup::AttributeParameterLookup()
|
||||
: LookupBase(QStringLiteral("AttributeParameterLookup"))
|
||||
{
|
||||
}
|
||||
|
||||
void DetailData::AttributeParameterLookup::addParameter(const QString &attributeType, const ParameterMap ¶meterMap)
|
||||
{
|
||||
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()) // exists? FIXME: in NGLDAO Timeline: "!=" !!
|
||||
return QVariant();
|
||||
|
||||
return *pmci;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE UI TYPE
|
||||
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); // -1 = invalid
|
||||
}
|
||||
|
||||
|
||||
// INTERPRETER LOOKUP
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ATTRIBUTE VALUE LOOKUP
|
||||
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()) // there are currently no values for this attribute type, insert all new values
|
||||
return; // attribute type not even found!
|
||||
|
||||
AttributeValueMap ¤tAttributeValueMap = *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) // add a VALUE (consisting of id & string) to the map coresponding to the attribute type
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
// ATTRIBUTE REDIRECTION LOOKUP
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Timeline
|
||||
+343
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Model to handle datail data for the different event types
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-09-04
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
#include <LtsUtilsCore/data_modification_enum.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
|
||||
#include <Services/ProjectDataManagement/pdm_enums.hpp> // needed for this header
|
||||
|
||||
#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; // HACK: there is no marker type
|
||||
|
||||
class DetailData : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class RequestResult
|
||||
{
|
||||
Error = 0,
|
||||
Okay = 1,
|
||||
InvalidAttributeType,
|
||||
NoValueTranslationForAttribute,
|
||||
NoUiTypeForAttribute,
|
||||
InvalidAttributeTypeJson,
|
||||
JsonCorrupted
|
||||
};
|
||||
|
||||
struct GetDetailDataForAttributeResult
|
||||
{
|
||||
QString attributeType; // translated! "Friendly Fire" instead of the key "FriendlyFire"
|
||||
QString attributeValue; // also translated! "No" instead of the key "0"
|
||||
|
||||
QString attributeTypeId; // "FriendlyFire" instead of the translated version "Friendly Fire"
|
||||
int attributeValueId = 0;
|
||||
RequestResult requestResult = RequestResult::Error;
|
||||
};
|
||||
|
||||
using GetDetailDataResultList = QVector<GetDetailDataForAttributeResult>;
|
||||
|
||||
enum AttributeUITypes // attribute ui types
|
||||
{
|
||||
ATTRIBUTE_UI_TYPE_TIME_RANGE_WIDGET = 0,
|
||||
ATTRIBUTE_UI_TYPE_DEFAULT_RANGE_WIDGET,
|
||||
ATTRIBUTE_UI_TYPE_AREA_RANGE_WIDGET,
|
||||
ATTRIBUTE_UI_TYPE_COMBO_BOX, // most attributes use this
|
||||
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, // ERROR VALUE
|
||||
//INTERPRETER_TYPE_TOINT,
|
||||
INTERPRETER_TYPE_RANGE,
|
||||
INTERPRETER_TYPE_AREA, // for filter interpreter
|
||||
INTERPRETER_TYPE_ID_COMPARE, // or key compare
|
||||
INTERPRETER_TYPE_STR_COMPARE, // or value compare [deprecated - do not use]
|
||||
INTERPRETER_TYPE_POSITION, // for event info windows line edits !
|
||||
INTERPRETER_TYPE_TIME, // for event info windows line edits !
|
||||
INTERPRETER_TYPE_DURATION, // for event info windows line edits !
|
||||
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:
|
||||
/**
|
||||
* @brief addRedirectedAttributeType just like "addAttributeType", but automatically redirects to "redirectionAttributeTypeId" (note that redirected attributes do not need to have ui types or interpreter types)
|
||||
* @param attributeTypeId
|
||||
* @param attributeText
|
||||
* @param redirectionAttributeTypeId
|
||||
*/
|
||||
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)
|
||||
{
|
||||
//qWarning() << "<<<" << attributeTypeId << ":" << (int)attributeEnum << "=>" << toString(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__; // do not allow secondary population, this would take to much time to develop atm
|
||||
|
||||
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 /* eventTypeId */, QString /* Event Name */>; // example: 3, 'Hit'
|
||||
|
||||
EventTypeLookup();
|
||||
|
||||
void addEventType(const int key, const QString &value);
|
||||
int getEventType(const QString &eventText) const;
|
||||
QString getEventText(const int eventType) const;
|
||||
QStringList getEventTexts() const; // all texts
|
||||
bool isEventExists(const int eventType) const;
|
||||
|
||||
private:
|
||||
EventTypeMap m_eventTypeMap;
|
||||
};
|
||||
EventTypeLookup eventTypeLookup;
|
||||
|
||||
|
||||
class AttributeTypeLookup : public LookupBase
|
||||
{
|
||||
public:
|
||||
using AttributeTypeLookupMap = QMap<QString /* attributeTypeId */, QString /* name */>;
|
||||
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 /* eventTypeId */, QList<QString> /* attributeTypeId List */>;
|
||||
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; // get all attribute types from the event
|
||||
|
||||
private:
|
||||
AttributeEventLookupMap m_attributeEventLookupMap;
|
||||
};
|
||||
AttributeEventLookup attributeEventLookup;
|
||||
|
||||
|
||||
class AttributeParameterLookup : public LookupBase // as ui type is fixed for attribute type, it is perfectly okay to request parameters (min, max, etc.) by attribute type
|
||||
{
|
||||
public:
|
||||
using ParameterMap = QMap<int, QVariant>; // Parameter Type => Parameter String
|
||||
using AttributeParameterMap = QHash<QString, ParameterMap>;
|
||||
|
||||
AttributeParameterLookup();
|
||||
|
||||
void addParameter(const QString &attributeType, const ParameterMap ¶meterMap); // add a parameter map to the lookup
|
||||
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); // add a VALUE (consisting of id & string) to the map coresponding to the attribute type
|
||||
void clear(); // clears map for updating map and sets to uninitialized
|
||||
|
||||
AttributeValueMap getAttributeValueMap(const QString &attributeType) const;
|
||||
QString getValueStringFromValueId(const QString &attributeType, const int attributeValueId, const QString &defaultValue = QString()) const;
|
||||
|
||||
private:
|
||||
AtributeValueLookupMap m_attributeTypeValueMap; // contains a map for each attribute type, that contain a map for their keys & values
|
||||
};
|
||||
AttributeValueLookup attributeValueLookup;
|
||||
|
||||
class AttributeValueLookupDtc : public LookupBase
|
||||
{
|
||||
public:
|
||||
AttributeValueLookupDtc() : LookupBase(QStringLiteral("AttributeValueLookupDtc")) {}
|
||||
~AttributeValueLookupDtc() { qDeleteAll(m_provider); }
|
||||
|
||||
// takes ownership on 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; // returns redirection, or if no redirection for attribute type, then returns original attribute type
|
||||
|
||||
private:
|
||||
AttributeRedirectionMap m_attributeRedirectionMap;
|
||||
};
|
||||
AttributeRedirectionLookup attributeRedirectionLookup;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,218 @@
|
||||
#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
|
||||
{
|
||||
|
||||
//m_rootItem->getFullEventList(true, true);
|
||||
static LtsTimelineClassic::EventList applyFilter(DetailData *detailData,
|
||||
const LtsTimelineClassic::EventList &eventList,
|
||||
const ModelFilterList &modelFilterList,
|
||||
bool simulation) // returns remaining/visible events
|
||||
{
|
||||
NGL::INGLLogger &logger(getLogger("ExconFilter"));
|
||||
/*
|
||||
*
|
||||
* general event can be filtered by event's default base data (time, duration, etc.)
|
||||
* .. and can be filtered by e.g. position (if the inherit event contains a position - if not, ignore error)
|
||||
*
|
||||
*/
|
||||
|
||||
//const QSet<int> eventOnlyEventList = getEventOnlyEventList(modelFilterList);
|
||||
//EventList eventList = eventListToFilter; //m_rootItem->getFullEventList(true, true); // get all events from model's root item, recursive and all (even hidden, logically) events
|
||||
LtsTimelineClassic::EventList visibleEvents;
|
||||
|
||||
bool resetFilterOnly = false;
|
||||
|
||||
if (!modelFilterList.count()) // no filters set = no events to filter => show all events
|
||||
{
|
||||
DEBUG_LOG(logger) << "applyFilter: Model Filter List is EMPTY";
|
||||
|
||||
if (simulation) // do not return any visible event if there is NO filter (or every event will be shown which is NOT a nice feature)
|
||||
return visibleEvents;
|
||||
|
||||
resetFilterOnly = true;
|
||||
}
|
||||
|
||||
visibleEvents = eventList; // copy list of pointers (!)
|
||||
|
||||
|
||||
QSet<int> mentionedEventTypes;
|
||||
mentionedEventTypes.insert(markerTypeId); // markers are always visible!
|
||||
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList)
|
||||
{
|
||||
if (mf.active)
|
||||
mentionedEventTypes.insert(mf.eventType);
|
||||
}
|
||||
|
||||
/* the filter must consider one of these 2 cases
|
||||
*
|
||||
* case 1: filter all events - if there is "General Event" only
|
||||
* case 2: case 1 + hide all events that are not mentioned - if there are other events than "General Event" AND the "General Event"
|
||||
*/
|
||||
|
||||
bool showAllEvents = false;
|
||||
|
||||
if (mentionedEventTypes.count() == 1 && mentionedEventTypes.contains(0 /* GENERAL_EVENT */))
|
||||
showAllEvents = true;
|
||||
|
||||
|
||||
// PER ATTRIBUTE THERE MUST BE AT LEAST ONE FITTING VALUE ! (or)
|
||||
for (LtsTimelineClassic::Event *event : eventList) // go through all events in model
|
||||
{
|
||||
if (!event)
|
||||
{
|
||||
WARNING_LOG(logger) << "applyFilter: Erroneous event!";
|
||||
continue; // next event, we can't handle this event
|
||||
}
|
||||
|
||||
int eventType = event->typeId();
|
||||
//int eventID = event->getID();
|
||||
|
||||
if (resetFilterOnly /*|| eventOnlyEventList.contains(eventType)*/) // reset filter or show entire event type when event type is event-type-filter (& search eoe list for current events event type)
|
||||
{
|
||||
if (!simulation)
|
||||
event->show();
|
||||
|
||||
// no inc / dec needed for vec here !
|
||||
|
||||
continue; // do not filter further - done!
|
||||
}
|
||||
|
||||
bool eventVisible = true;
|
||||
|
||||
// check if event must be filtered (mentioned in model filter list)
|
||||
if (!showAllEvents && !mentionedEventTypes.contains(eventType))
|
||||
eventVisible = false;
|
||||
|
||||
if (!eventVisible /*&& m_showOnlyThese*/) // TODO: settings for "SHOW ALL BUT FILTER ONLY THESE" and "SHOW ONLY THESE"
|
||||
{
|
||||
if (!simulation)
|
||||
event->hide();
|
||||
|
||||
visibleEvents.removeAll(event);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto eventsAttributeList = detailData->attributeEventLookup.getEventsAttributeList(eventType); // get attribute types from event
|
||||
|
||||
// at least one value has to fit per attribute !! (or)
|
||||
for (const QString &attributeType : eventsAttributeList) // attribute of event [[ATTR]]
|
||||
{
|
||||
QString concreteAttributeType = detailData->attributeRedirectionLookup.getRedirection(attributeType); // why did I not "get the concrete type in any case" back then?
|
||||
bool visibleByAttribute = false; // false from the beginning, because at least one value HAS TO FIT to an attribute
|
||||
bool attributeTypeMentioned = false; // if not filtered by an attribute, then do not filter by this attribute
|
||||
|
||||
|
||||
// no fitting value? then hide event
|
||||
for (const FilterWorker::ModelFilter &mf : modelFilterList) // values from filter list [[VAL]]
|
||||
{
|
||||
if (mf.eventType == eventType || mf.eventType == 0 /* GENERAL_EVENT */) // if true, there are only ModelFilters for General Event (which filters all events) [General Event's attributes get applied on all other Events]
|
||||
{
|
||||
if (mf.attributeType == concreteAttributeType && mf.active) // the attribute from the event looking for?
|
||||
{
|
||||
attributeTypeMentioned = true; // actually filtering by this attribute !
|
||||
|
||||
DetailData::GetDetailDataForAttributeResult result = detailData->getDetailDataForAttribute(event, attributeType); // get attribute from event detail data (zwmsdd)
|
||||
if (result.requestResult != DetailData::RequestResult::Okay) // detail data not found for attr type? must be a redirection
|
||||
result = detailData->getDetailDataForAttribute(event, concreteAttributeType); // TRY REDIRECTION
|
||||
|
||||
/* filter says: look for detail data with attr type "area_pos" => must be redirected before doing this to "position"
|
||||
* filter says: look for "attribute verursacher" => do NOT redirect as this is an existing detail data! */
|
||||
|
||||
/* attribute types with ui type for combobox can redirect unproblematically (same as in filter equation functions)
|
||||
* => attribute types with special ui type(s) should not be redirected
|
||||
* so if the attempt to lookup a attribute interpreter type fails, try another lookup with redirection
|
||||
* side effects: when new attribute types are not completly integrated
|
||||
* guess: ????
|
||||
*/
|
||||
|
||||
if (result.requestResult != DetailData::RequestResult::Okay) // detail data not found for attr type? must be a redirection
|
||||
{
|
||||
WARNING_LOG(logger) << "applyFilter: result.requestResult != DetailData::OKAY -" << (int)result.requestResult;
|
||||
continue; // // TODO: show error and continue
|
||||
}
|
||||
|
||||
//qWarning() << "checkValue: type" << concreteAttributeType << "value id" << result.attributeValueId << "filter value" << mf.attributeValue << "(value as string:"<<result.attributeValue<<")";
|
||||
visibleByAttribute = FilterEquationFunctions::checkValue(detailData, concreteAttributeType, result.attributeValueId, mf.attributeValue);
|
||||
|
||||
if (visibleByAttribute) // the event is visible if minimum ONE attribute fits
|
||||
break;
|
||||
|
||||
#ifdef DEBUG // as it is time consuming
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// at the end, after looping through all values - no value fitting: hide | at least one value fitting: show
|
||||
if (attributeTypeMentioned && !visibleByAttribute) // if attribute is mentioned, but NOT marked as visible, then hide event - because one WHOLE attribute does not fit !
|
||||
{
|
||||
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)
|
||||
{
|
||||
/*/
|
||||
*
|
||||
* Filter Text:
|
||||
*
|
||||
* Syntax : [Filter];[Filter]; ...
|
||||
* Filter : [Event Type]:[Attribute]+[Attribute]+ ...
|
||||
* Attribute : [Attr Type]{[Attr Value],[Attr Value], ...}
|
||||
*
|
||||
/*/
|
||||
|
||||
LtsTimelineClassic::EventList visibleEvents;
|
||||
|
||||
FilterWorker::GetModelFilterListResult result = FilterWorker::getModelFilterList(detailData, filter, true /* type safe !! */); // get model filter list by the filter text
|
||||
ModelFilterList modelFilterList = result.result;
|
||||
if (handleResult)
|
||||
FilterWorker::getInstance()->handleResultValues(result.resultValueList, parentWidget);
|
||||
|
||||
visibleEvents = applyFilter(detailData, eventListToFilter, modelFilterList, simulation); // apply the model filter list to the timeline
|
||||
|
||||
|
||||
return visibleEvents;
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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,37 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Building - logging facility
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Logging for BuildingViewer
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Patric Karwat, SLSE, 2016-08-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,111 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ExerciseManangement - Exercise Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#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++ /* pun not intended */, 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")); // add live events from its own cache
|
||||
m_ui->lblEventCount->setText(QString::number(eventCount));
|
||||
|
||||
|
||||
for (int i = 0; i < m_ui->twCaches->columnCount(); i++)
|
||||
{
|
||||
m_ui->twCaches->resizeColumnToContents(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ExerciseManangement - Exercise Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#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);
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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>
|
||||
+1085
File diff suppressed because it is too large.
Load diff
+174
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ExerciseManangement - Exercise Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#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>
|
||||
|
||||
// Replay
|
||||
#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); // no const ref because markerTypeId might be added
|
||||
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; // in msecs
|
||||
|
||||
// dtc's
|
||||
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;
|
||||
|
||||
// foreign gui's
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
+215
@@ -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><html><head/><body><p><span style=" color:#ff5656;">Please create at least one filter of any event type to see events.</span></p></body></html></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,209 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Timeline Model for DDS
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2017-03-31
|
||||
*/
|
||||
|
||||
#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; // events currently visible/set on timeline?
|
||||
};
|
||||
|
||||
|
||||
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; } // for debug only !
|
||||
const CacheRange &liveCache() const { return m_liveCache; } // for debug only !
|
||||
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;
|
||||
//void addExerciseEventManagementEvent(const ExerciseEventManagement::Event &data);
|
||||
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); // returns false if NOT added (so delete the event if false)
|
||||
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;
|
||||
//const QVector<LtsTimelineClassic::Event *> createEvents(const QVector<ExerciseEventManagement::Event> &eventList) 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 forceUncache();
|
||||
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; // per range in m_cachedEvents
|
||||
int m_maxCacheRanges; // max entries in m_cachedEvents
|
||||
int m_eventCount;
|
||||
|
||||
qint64 m_lastCachedEventsId;
|
||||
QVector<QPair<qint64, CacheRange>> m_cachedEvents;
|
||||
|
||||
CacheRange m_liveCache;
|
||||
bool m_createFakeEvents;
|
||||
QSet<int> m_activeEventTypeIds;
|
||||
//bool m_dtorEmergencyMode;
|
||||
QVector<int> m_knownMarkerIds;
|
||||
NGL::INGLLogger &m_logger;
|
||||
|
||||
|
||||
public slots:
|
||||
void slotAddLiveEvent(const ExerciseEventManagement::Event &event);
|
||||
|
||||
|
||||
private slots:
|
||||
//void slotEventChanged(const ExerciseEventManagement::Event &data, DataModification modType);
|
||||
void slotMarkerChanged(const MarkerManagement::Marker &data, DataModification modType);
|
||||
void slotAddLiveEventsFake();
|
||||
void slotRequestMessageReceived(const QString &message);
|
||||
|
||||
|
||||
signals:
|
||||
void signalTooMuchEvents();
|
||||
void signalRebuildTimelineKnownRanges(); // sadly, the model cannot do this..
|
||||
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();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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; //TODO: Project Settings ?
|
||||
|
||||
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 // don't show markers - the proxy model filters all markers out .... and the sort methods don't seem to be different from default
|
||||
{
|
||||
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(); // just in case
|
||||
m_model->setInvalid(); // just in case
|
||||
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; // must be sorted by visualIndex
|
||||
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)) // don't offer concealed columns to be shown
|
||||
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;
|
||||
|
||||
// sorted by visual index
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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; // original
|
||||
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();
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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,213 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ComboBox's popup, optimized for tablets (bigger dropdown/popup)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2016-03-09
|
||||
*/
|
||||
|
||||
#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*>());
|
||||
|
||||
// assumption: m_columns is sorted by visual index
|
||||
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)
|
||||
{
|
||||
// should never happens since we write the json file...
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ComboBox's popup, optimized for tablets (bigger dropdown/popup)
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2016-03-09
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The EventListColumns is a popup window (LtsFramelessDialog) with a list of QCheckboxes.
|
||||
* This is a custom Popup which is touch-friendly and screen-centered.
|
||||
*/
|
||||
class EventListColumns : public LtsWidgets::LtsFramelessDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief EventListColumns creates a popup with all its items (from model) in it
|
||||
* @param model the model which contains all items
|
||||
* @param parent parent of this widget
|
||||
*/
|
||||
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;
|
||||
|
||||
};
|
||||
} // namespace
|
||||
@@ -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,268 @@
|
||||
#include "tln_event_list_model.h"
|
||||
#include "detail_data.h" // marker type
|
||||
|
||||
#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("Battery State"),
|
||||
// tr("Bite State"),
|
||||
tr("Building"),
|
||||
tr("Charge Type"),
|
||||
tr("Charge Remain"),
|
||||
// tr("Config State"),
|
||||
tr("Damage Percent"),
|
||||
tr("Damage Percent Old"),
|
||||
// tr("Device Type"),
|
||||
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();
|
||||
// ERROR_LOG(m_logger) << "Event details #: " << obj.count();
|
||||
// for (auto i = obj.constBegin(); i != obj.constEnd(); ++i)
|
||||
// ERROR_LOG(m_logger) << "Key = " << i.key() << " Value = " << i.value().toString();
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case EventListDialogModel::Columns::Id:
|
||||
return event->uniqueId();
|
||||
case EventListDialogModel::Columns::Type:
|
||||
{
|
||||
if (event->typeId() == markerTypeId /* marker */)
|
||||
return tr("Marker");
|
||||
|
||||
return ProjectDataManagement::toString(static_cast/*not the best idea*/<ProjectDataManagement::EventType::type>(event->typeId()));
|
||||
}
|
||||
case EventListDialogModel::Columns::Time:
|
||||
return QDateTime::fromMSecsSinceEpoch(event->startTime()); //, DTG::Short
|
||||
case EventListDialogModel::Columns::Duration:
|
||||
return (event->duration() / 1000);
|
||||
case EventListDialogModel::Columns::Party:
|
||||
{
|
||||
if (event->typeId() == ProjectDataManagement::EventType::HitBuilding) // don't show any text on Hit Building as a building can't have a party
|
||||
break;
|
||||
return ParticipantManagement::trPartyName(m_ppmDtc->party(event->partyId()).name());
|
||||
}
|
||||
case EventListDialogModel::Columns::EquipNo:
|
||||
{
|
||||
if (event->typeId() == ProjectDataManagement::EventType::HitBuilding) // don't show any text on Hit Building as a building can't have a party
|
||||
break;
|
||||
return event->equipmentId();
|
||||
}
|
||||
case EventListDialogModel::Columns::Hierarchy:
|
||||
return m_ppmDtc->hierarchyFromParticipant(event->playerId());
|
||||
case EventListDialogModel::Columns::ParticipantId:
|
||||
return event->playerId();
|
||||
|
||||
// TODO: fill data
|
||||
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::BatteryState:
|
||||
{
|
||||
if (!obj.contains(QStringLiteral("BatteryState")))
|
||||
return QVariant();
|
||||
return obj[QStringLiteral("BatteryState")].toInt();
|
||||
}
|
||||
case EventListDialogModel::BiteState:
|
||||
{
|
||||
if (!obj.contains(QStringLiteral("BiteState")))
|
||||
return QVariant();
|
||||
return obj[QStringLiteral("BiteState")].toInt();
|
||||
}
|
||||
case EventListDialogModel::ConfigState:
|
||||
{
|
||||
if (!obj.contains(QStringLiteral("ConfigState")))
|
||||
return QVariant();
|
||||
return obj[QStringLiteral("ConfigState")].toInt();
|
||||
}
|
||||
case EventListDialogModel::DeviceType:
|
||||
{
|
||||
if (!obj.contains(QStringLiteral("DeviceType")))
|
||||
return QVariant();
|
||||
return obj[QStringLiteral("DeviceType")].toVariant();
|
||||
}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// EventListProxyModel
|
||||
//
|
||||
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) // not showing Markers in list model
|
||||
return false;
|
||||
return LtsWidgets::LtsColumnFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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,
|
||||
// BatteryState, //opt
|
||||
// BiteState, //opt
|
||||
Building,
|
||||
ChargeType,
|
||||
ChargeRemain,
|
||||
// ConfigState, //opt
|
||||
DamagePercent,
|
||||
DamagePercentOld,
|
||||
// DeviceType, //opt
|
||||
FriendlyFire,
|
||||
GearType,
|
||||
// OriginatorType, //opt
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,327 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ExerciseManangement - Exercise Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#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(); // apply() always returns false (because it can't be executed with async ops), resulting in the window not closing on OK - only use apply button until apply() can have async ops
|
||||
|
||||
connect(m_ui->cbCheckAll, &QCheckBox::toggled,
|
||||
this, [this](bool toggled)
|
||||
{
|
||||
const auto cbList = findChildren<QCheckBox *>();
|
||||
for (QCheckBox *cb : cbList)
|
||||
{
|
||||
if (cb == m_ui->cbCheckAll) // needed? maybe recursion?
|
||||
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();
|
||||
// first, deactivate all checkboxes, as we can't keep track on WHICH event types are now inactive
|
||||
|
||||
const QList<QCheckBox *> cbs(findChildren<QCheckBox *>()); // yes, even the "check all" cb
|
||||
|
||||
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::Unknown,
|
||||
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::HitMine, // HitEffectSimulation
|
||||
// ProjectDataManagement::EventType::HitN, // HitEffectSimulation
|
||||
// ProjectDataManagement::EventType::HitC, // HitEffectSimulation
|
||||
// ProjectDataManagement::EventType::EnterDangerArea, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::LeaveDangerArea, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::EnterMineArea, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::LeaveMineArea, // showEnterLeaveEvents
|
||||
ProjectDataManagement::EventType::CrossLocalBorderline,
|
||||
// ProjectDataManagement::EventType::EnterFunctionalArea, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::LeaveFunctionalArea, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::EnterNuclear, // showEnterLeaveEvents
|
||||
// ProjectDataManagement::EventType::LeaveNuclear, // showEnterLeaveEvents
|
||||
ProjectDataManagement::EventType::CrossGlobalBorderline,
|
||||
// ProjectDataManagement::EventType::HitB, // HitEffectSimulation
|
||||
// ProjectDataManagement::EventType::FriendlyFire, // currently not displayed
|
||||
// ProjectDataManagement::EventType::HitGasPipe, // HitEffectSimulation
|
||||
// ProjectDataManagement::EventType::MineArea, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::NContamination, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::BCContamination, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::DangerArea, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::FunctionalArea, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::MineCorridor, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::Borderline, // showEffectSimulationEvents
|
||||
// ProjectDataManagement::EventType::TechnicalArea,
|
||||
// ProjectDataManagement::EventType::GasPipe, // separate
|
||||
// ProjectDataManagement::EventType::EquipmentErrorReport,
|
||||
// ProjectDataManagement::EventType::EmergencyCall,
|
||||
});
|
||||
|
||||
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;
|
||||
//ret += ProjectDataManagement::EventType::HitGasPipe; covered by HitEffectSimulation yes or no ??
|
||||
}
|
||||
|
||||
const bool showPvSan = LtsUtils::ProjectSettings::isFunctionEnabled(QStringLiteral("ParticipantInformation"),
|
||||
QStringLiteral("HasPvSan"));
|
||||
if (showPvSan)
|
||||
ret += ProjectDataManagement::EventType::Sanitation;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// helper for grouped sorting
|
||||
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; // dummy
|
||||
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; // 0 is 'Check all'
|
||||
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; // because this has to happen async.. (reset changes after async ops are (successfully) done)
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
|
||||
//
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* ExerciseManangement - Exercise Overview Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -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,521 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Show Details Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Iuliana Ojog, SLSE, 2017-05-22
|
||||
*/
|
||||
|
||||
#include "tln_show_details.h"
|
||||
#include "ui_tln_show_details.h"
|
||||
#include "tln_view_gui_plugin.h"
|
||||
#include "detail_data.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <LtsWidgets/lts_base.h>
|
||||
#include <ngltools/ngltools_dtg.h>
|
||||
#include <LtsTimelineClassic/Event.h>
|
||||
#include <LtsSession/lts_session.h>
|
||||
#include <LtsSession/lts_session_data.h>
|
||||
#include <Services/ProjectDataManagement/pdm_translation.h>
|
||||
#include <AudioVideoManagement/stream_name_mapping.h>
|
||||
#include <Plugins/MarkerManagement/Gui/Common/mrk_apply_filter.h>
|
||||
#include <Plugins/SituationReplay/srp_gui_plugin_interface.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonValue>
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
*
|
||||
* This Dialog uses foreign gui ifcs from a Session that is not ours!
|
||||
* If we have the last shared_ptr to a foreign Session's foreign Ifc,
|
||||
* and our Dialog gets deleted AFTER the foreign Session was killed,
|
||||
* then we trigger the deletion of the dead foreign Ifc of a DEAD SESSION.
|
||||
* So ifc shared_ptrs are fetched when needed and removed directly after use.
|
||||
*
|
||||
* Shared Pointers.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace Timeline
|
||||
{
|
||||
|
||||
ShowDetailsDialog::ShowDetailsDialog(QWidget *parent)
|
||||
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
|
||||
, m_ui(new Ui::ShowDetailsDialog)
|
||||
, m_logger(getLogger("ShowDetailsDialog"))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setUnchangeable();
|
||||
|
||||
m_ui->debugWidget->hide();
|
||||
|
||||
connect(m_ui->pbStartReplay, &QPushButton::clicked,
|
||||
this, &ShowDetailsDialog::slotStartReplay);
|
||||
|
||||
connect(m_ui->pbShowMarker, &QPushButton::clicked,
|
||||
this, &ShowDetailsDialog::slotShowMarker);
|
||||
|
||||
connect(m_ui->pbPlayback, &QPushButton::clicked,
|
||||
this, &ShowDetailsDialog::slotStartPlayback);
|
||||
|
||||
connect(m_ui->pbFocus, &QPushButton::clicked,
|
||||
this, &ShowDetailsDialog::slotFocusOnMap);
|
||||
|
||||
m_ui->tbFocus->hide();
|
||||
m_ui->tbMarker->hide();
|
||||
m_ui->tbPlayback->hide();
|
||||
m_ui->tbReplay->hide();
|
||||
|
||||
#ifndef LTS_DEBUG
|
||||
if (LtsSessionData::LtsSessionData::getInstance()->debugFlagValue(QStringLiteral("Timeline.Debug")) == QVariant(true))
|
||||
#endif
|
||||
{
|
||||
m_ui->debugWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
ShowDetailsDialog::~ShowDetailsDialog()
|
||||
{
|
||||
m_session = nullptr;
|
||||
m_mrkDtc = nullptr;
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::retranslate()
|
||||
{
|
||||
translate(m_ui, m_eventType, false, tr("Event"));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::slotFocusOnMap()
|
||||
{
|
||||
if (m_replayAppSession == nullptr)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no replay app, no focus";
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<SituationMap::ForeignGuiInterface> sitMapIfc;
|
||||
|
||||
if (!m_replayAppSession->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(sitMapIfc))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "no sitMapIfc, no focusing on replay in Show Details Dialog 1";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sitMapIfc)
|
||||
{
|
||||
WARNING_LOG(m_logger) << "no sitMapIfc, no focusing on replay in Show Details Dialog 2";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_event->typeId() != markerTypeId) // NOTE: marker events have their position stored in the map settings
|
||||
{
|
||||
if (!m_event->positionValid())
|
||||
{
|
||||
WARNING_LOG(m_logger) << "event has no valid position, skip focusOnMap";
|
||||
return;
|
||||
}
|
||||
|
||||
// x == lon ; y == lat
|
||||
sitMapIfc->setCenterPoint(m_event->pos2d());
|
||||
}
|
||||
|
||||
const QJsonObject root(m_event->detailData());
|
||||
const QJsonValue mapSettings(root[QStringLiteral("MapSettings")]);
|
||||
|
||||
if (!mapSettings.isUndefined())
|
||||
sitMapIfc->setOperatorMapSettings(mapSettings);
|
||||
|
||||
const QJsonValue filterSettings(root[QStringLiteral("Filter")]);
|
||||
if (!filterSettings.isUndefined())
|
||||
{
|
||||
MarkerManagement::MarkerManagementApplyFilter applyFilter(m_replayAppSession, m_fltParticipantIfc, m_fltAesIfc, m_fltBuildingComponentIfc);
|
||||
if (!applyFilter.applyFilter(filterSettings.toObject()))
|
||||
{
|
||||
WARNING_LOG(m_logger) << "filters from event #"<<m_event->uniqueId()<<" could not be applied";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::slotShowMarker()
|
||||
{
|
||||
m_mrkIfc->showMarker(m_event->uniqueId());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::hasNameAndEndTime() const
|
||||
{
|
||||
QString dummy1;
|
||||
qint64 dummy2;
|
||||
return getStreamNameAndEndTime(dummy1, dummy2, true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::getStreamNameAndEndTime(QString &streamName, qint64 &endTime, bool silent) const
|
||||
{
|
||||
const QJsonObject root(m_event->detailData());
|
||||
const QString _streamName = root[QStringLiteral("streamName")].toString(); // Lts/Services/ExerciseEventManagement/web_socket_avs.cpp:160
|
||||
|
||||
if (_streamName.isEmpty())
|
||||
{
|
||||
if (!silent)
|
||||
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartVideo(): stream name is empty " << QJsonDocument(m_event->detailData()).toJson();
|
||||
return false;
|
||||
}
|
||||
|
||||
qint64 _endTime = root[QStringLiteral("endTime")].toDouble(0);
|
||||
|
||||
if (_endTime == 0 && !silent)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::slotStartPlayback: event " << m_event->uniqueId() << " has no end time!";
|
||||
|
||||
streamName = _streamName;
|
||||
endTime = _endTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::slotStartPlayback()
|
||||
{
|
||||
QString streamName;
|
||||
qint64 endTime;
|
||||
|
||||
if (!getStreamNameAndEndTime(streamName, endTime))
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot start playback as this event's informations are missing."));
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isAudio = isAudioEventType(m_event->typeId());
|
||||
if (!m_avmIfc->startAudioVideoPlayback(streamName, m_event->startTime(), isAudio))
|
||||
new LtsWidgets::LtsMessageDialogNew(this, tr("Playback cannot be started because of an error. Please try again later."));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::slotStartReplay()
|
||||
{
|
||||
if (m_replayAppSession == nullptr)
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartReplay: no replay app, no replay";
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> srpIfc;
|
||||
|
||||
if (!m_replayAppSession->getForeignGuiInterface<SituationReplay::ForeignGuiInterface>(srpIfc))
|
||||
{
|
||||
ERROR_LOG(m_logger) << "ShowDetailsDialog::slotStartReplay: no srp, no replay in Show Details Dialog";
|
||||
return;
|
||||
}
|
||||
|
||||
srpIfc->startReplay(m_event->startTime() - (10 * 1000) /* TODO: offset? */); // TODO: endTime..
|
||||
slotFocusOnMap();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
void ShowDetailsDialog::setButtonDisabled(QPushButton *button, QToolButton *warningButton, const QString &reasonMessage, bool hide)
|
||||
{
|
||||
if (hide)
|
||||
button->setVisible(false);
|
||||
button->setEnabled(false);
|
||||
button->setToolTip(reasonMessage);
|
||||
warningButton->setToolTip(reasonMessage);
|
||||
warningButton->show();
|
||||
|
||||
connect(warningButton, &QToolButton::clicked,
|
||||
warningButton, [this, warningButton]()
|
||||
{
|
||||
LtsWidgets::LtsMessageDialog::showMessage(this, warningButton->toolTip());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::isMarkerAudioVideo() const
|
||||
{
|
||||
const QJsonObject root(m_event->detailData());
|
||||
|
||||
return (root[QStringLiteral("IsAudioType")].toBool(false) || root[QStringLiteral("IsVideoType")].toBool(false));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::isAvsCapable(const LtsTimelineClassic::Event *event)
|
||||
{
|
||||
const int eventType = event->typeId();
|
||||
return isAvEventType(eventType) || eventType == Timeline::markerTypeId;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::isHitEventType(int eventTypeId)
|
||||
{
|
||||
return (eventTypeId == ProjectDataManagement::EventType_def::Hit ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitB ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitBuilding ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitC ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitGasPipe ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitEffectSimulation ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitMine ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::HitN);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::isAvEventType(int eventTypeId)
|
||||
{
|
||||
return (isAudioEventType(eventTypeId) ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::CameraVideo);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::isAudioEventType(int eventTypeId)
|
||||
{
|
||||
return (eventTypeId == ProjectDataManagement::EventType_def::RadioCnr ||
|
||||
eventTypeId == ProjectDataManagement::EventType_def::RadioTvc);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
bool ShowDetailsDialog::init(DetailData *detailData, const LtsTimelineClassic::Event *event,
|
||||
const QPointer<LtsSession::LtsSession> &session,
|
||||
const QPointer<LtsSession::LtsSession> &replayAppSession,
|
||||
const std::shared_ptr<AudioVideoManagement::ForeignMenuEditGuiInterface> &avmIfc,
|
||||
const std::shared_ptr<MarkerManagement::ForeignGuiInterface> &mrkIfc,
|
||||
const std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> &fltParticipantIfc,
|
||||
const std::shared_ptr<FilterManagement::ForeignAesGuiInterface> &fltAesIfc,
|
||||
const std::shared_ptr<FilterManagement::ForeignFltBuildingComponentGuiInterface> &fltBuildingComponentIfc,
|
||||
bool isTimelineApp,
|
||||
QWidget *pseudoParent,
|
||||
AudioVideoManagement::StreamNameMapping *streamNameMapping)
|
||||
{
|
||||
m_session = session;
|
||||
//Q_ASSERT(streamNameMapping);
|
||||
// m_srpIfc = srpIfc; << from replay app
|
||||
// m_sitMapIfc = sitMapIfc; << from replay app
|
||||
|
||||
std::shared_ptr<SituationReplay::ForeignGuiInterface> srpIfc;
|
||||
std::shared_ptr<SituationMap::ForeignGuiInterface> sitMapIfc;
|
||||
if (!m_session->getDtc<MarkerManagement::DataInterface>(m_mrkDtc))
|
||||
WARNING_LOG(m_logger) << "!m_session->getDtc<MarkerManagement::DataInterface>(m_mrkDtc)";
|
||||
|
||||
m_mrkDtc->enableMarker();
|
||||
|
||||
connect(m_mrkDtc.get(), &MarkerManagement::Interface::Dtc::markerChanged,
|
||||
this, &ShowDetailsDialog::updateMarker);
|
||||
|
||||
|
||||
if (replayAppSession != nullptr)
|
||||
{
|
||||
m_replayAppSession = replayAppSession;
|
||||
|
||||
connect(replayAppSession.data(), &LtsSession::LtsSession::destroyed,
|
||||
this, [this]()
|
||||
{
|
||||
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("No map available."));
|
||||
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Situation Replay App not started."));
|
||||
});
|
||||
|
||||
if (!replayAppSession->getForeignGuiInterface<SituationReplay::ForeignGuiInterface>(srpIfc))
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no srp, no replay in Show Details Dialog";
|
||||
|
||||
if (!replayAppSession->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(sitMapIfc))
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no sitMapIfc, no focusing on replay in Show Details Dialog";
|
||||
}
|
||||
|
||||
m_avmIfc = avmIfc;
|
||||
m_mrkIfc = mrkIfc;
|
||||
m_fltParticipantIfc = fltParticipantIfc;
|
||||
m_fltAesIfc = fltAesIfc;
|
||||
m_fltBuildingComponentIfc = fltBuildingComponentIfc;
|
||||
m_streamNameMapping = streamNameMapping;
|
||||
|
||||
if (m_avmIfc == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no avm ifc given";
|
||||
|
||||
if (m_mrkIfc == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no mrk ifc given";
|
||||
|
||||
if (m_fltParticipantIfc == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt Part ifc given";
|
||||
|
||||
if (m_fltAesIfc == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt Aes ifc given";
|
||||
|
||||
if (m_fltBuildingComponentIfc == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no flt buildingComponent ifc given";
|
||||
|
||||
if (m_streamNameMapping == nullptr)
|
||||
WARNING_LOG(m_logger) << "ShowDetailsDialog::init: no stream name mapping given";
|
||||
|
||||
m_event = event;
|
||||
int eventTypeId = event->typeId();
|
||||
|
||||
// hide equipment id labels if event has no eq id
|
||||
if (event->equipmentId() <= 0)
|
||||
{
|
||||
m_ui->lblEquipNo->hide();
|
||||
m_ui->lblValueEquipNo->hide();
|
||||
}
|
||||
else
|
||||
m_ui->lblValueEquipNo->setText(QString::number(event->equipmentId()));
|
||||
|
||||
connect(pseudoParent, &QWidget::destroyed, this, &ShowDetailsDialog::deleteLater);
|
||||
|
||||
QString eventTime;
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
eventTime = QStringLiteral("%1 <font color='#aebac6'>(%2)</font>").arg(DTG::toStringMSec(event->startTime())).arg(event->startTime());
|
||||
else
|
||||
eventTime = DTG::toStringMSec(event->startTime());
|
||||
|
||||
m_ui->lblValueEventTime->setText(eventTime);
|
||||
m_eventType = detailData->eventTypeLookup.getEventText(eventTypeId);
|
||||
|
||||
if (m_eventType.isEmpty())
|
||||
m_eventType = tr("<unknown> (%1)").arg(eventTypeId);
|
||||
|
||||
if (sitMapIfc == nullptr || isTimelineApp)
|
||||
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("No map available"), true);
|
||||
else if (eventTypeId != markerTypeId && !m_event->positionValid()) // NOTE: markers get their position from the map settings !
|
||||
setButtonDisabled(m_ui->pbFocus, m_ui->tbFocus, tr("Event has an invalid position and cannot be focused"));
|
||||
|
||||
if (srpIfc == nullptr)
|
||||
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Situation Replay App not started."));
|
||||
else if (sitMapIfc == nullptr)
|
||||
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("This app has no map to focus this event on."));
|
||||
else if (eventTypeId != markerTypeId && !m_event->positionValid()) // NOTE: markers get their position from the map settings !
|
||||
setButtonDisabled(m_ui->pbStartReplay, m_ui->tbReplay, tr("Event has an invalid position, cannot be focused and therefore has no replay capability."));
|
||||
|
||||
if (eventTypeId != markerTypeId)
|
||||
setButtonDisabled(m_ui->pbShowMarker, m_ui->tbMarker, tr("This event is not a marker."), true);
|
||||
else if (m_mrkIfc == nullptr)
|
||||
setButtonDisabled(m_ui->pbShowMarker, m_ui->tbMarker, tr("This app has no marker interface available."), true);
|
||||
|
||||
if (!isAvsCapable(event))
|
||||
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This event is not an audio/video type."), true);
|
||||
else if (m_avmIfc == nullptr)
|
||||
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This app has no audio/video interface available."), true);
|
||||
else if (eventTypeId == Timeline::markerTypeId && !isMarkerAudioVideo())
|
||||
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This marker event is not an audio / video type."), true);
|
||||
else if (!hasNameAndEndTime())
|
||||
setButtonDisabled(m_ui->pbPlayback, m_ui->tbPlayback, tr("This event has missing informations about the playback."));
|
||||
|
||||
|
||||
// Button im Ereignisfenster abhaengig vom Eventtyp ausblenden
|
||||
if (isAvsCapable(event))
|
||||
{
|
||||
m_ui->pbFocus->hide();
|
||||
m_ui->tbFocus->hide();
|
||||
m_ui->pbStartReplay->hide();
|
||||
m_ui->tbReplay->hide();
|
||||
}
|
||||
|
||||
const DetailData::GetDetailDataResultList result = detailData->getDetailData(event);
|
||||
QLocale locale; // uses system locale
|
||||
|
||||
for (const DetailData::GetDetailDataForAttributeResult &attributeDetail : result)
|
||||
{
|
||||
// do not add time again
|
||||
if (detailData->attributeInterpreterLookup.getInterpreterType(attributeDetail.attributeTypeId) == DetailData::INTERPRETER_TYPE_TIME)
|
||||
continue;
|
||||
|
||||
QString attributeTypeText;
|
||||
QString attributeValueText;
|
||||
|
||||
if (attributeDetail.requestResult != DetailData::RequestResult::Okay)
|
||||
{
|
||||
if (attributeDetail.requestResult == DetailData::RequestResult::NoValueTranslationForAttribute) // attribute type valid, but no attribute value, but a attribute value id is given - show the id!
|
||||
{
|
||||
attributeTypeText = attributeDetail.attributeType;
|
||||
attributeValueText = QStringLiteral("%1 (%2)").arg(tr("<unknown>")).arg(attributeDetail.attributeValueId);
|
||||
}
|
||||
else if (attributeDetail.requestResult == DetailData::RequestResult::InvalidAttributeType)
|
||||
{
|
||||
// an attribute which we don't handle, it's fine
|
||||
DEBUG_LOG(m_logger) << "Unhandled attribute " << attributeDetail.attributeTypeId << " - skipping";
|
||||
continue;
|
||||
}
|
||||
else // everything went wrong, only show unknown ids for both key and value
|
||||
{
|
||||
attributeTypeText = QStringLiteral("%1 (%2)").arg(tr("<unknown>"), attributeDetail.attributeTypeId);
|
||||
attributeValueText = tr("<type unknown>");
|
||||
|
||||
WARNING_LOG(m_logger) << "getDetailData failed with message id " << (int)attributeDetail.requestResult << " for attribute " << attributeDetail.attributeTypeId;
|
||||
continue; // do not add unknown types
|
||||
}
|
||||
}
|
||||
else // everything worked fine:
|
||||
{
|
||||
attributeTypeText = attributeDetail.attributeType;
|
||||
|
||||
// user readability
|
||||
bool isNumber = false;
|
||||
qint64 attributeValueAsNumber = attributeValueText.toLongLong(&isNumber);
|
||||
if (isNumber)
|
||||
attributeValueText = locale.toString(attributeValueAsNumber);
|
||||
|
||||
if (m_logger.isDebugEnabled())
|
||||
attributeValueText = QStringLiteral("%1 <font color='#aebac6'>(%2)</font>").arg(attributeDetail.attributeValue).arg(attributeDetail.attributeValueId);
|
||||
else
|
||||
attributeValueText = attributeDetail.attributeValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString attributeType(attributeDetail.attributeTypeId);
|
||||
|
||||
// leave some attributes out ...
|
||||
int eventType = event->typeId();
|
||||
if (isAudioEventType(eventType))
|
||||
{
|
||||
if (attributeType == QStringLiteral("MainStructureElementId"))
|
||||
continue;
|
||||
}
|
||||
else if (isHitEventType(eventType))
|
||||
{
|
||||
if (attributeType == QStringLiteral("OriginatorType"))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attributeType == QStringLiteral("GearId")) // never show gear id
|
||||
continue;
|
||||
|
||||
|
||||
|
||||
|
||||
QLabel *attributeValueTextLabel = new QLabel(attributeValueText);
|
||||
DEBUG_LOG(m_logger) << "attributeValueText=" << attributeValueText;
|
||||
attributeValueTextLabel->setTextInteractionFlags(attributeValueTextLabel->textInteractionFlags() | Qt::TextInteractionFlag::TextSelectableByMouse);
|
||||
DEBUG_LOG(m_logger) << "attributeTypeText=" << attributeTypeText
|
||||
<< " attributeValueTextLabel=" << attributeValueTextLabel;
|
||||
m_ui->formLayout->addRow(new QLabel(attributeTypeText), attributeValueTextLabel);
|
||||
}
|
||||
|
||||
if (m_eventType.isEmpty())
|
||||
m_eventType = QStringLiteral("%1 (%2)").arg(tr("<unknown>"), ProjectDataManagement::toString(static_cast<ProjectDataManagement::EventType::type>(event->typeId())));
|
||||
m_ui->lblEventType->setText(QStringLiteral("<b>%1</b>").arg(m_eventType));
|
||||
|
||||
m_ui->pteDetailDataTest->setPlainText(QString::fromUtf8(QJsonDocument(event->detailData()).toJson()));
|
||||
|
||||
QString pos(QStringLiteral("x: %1 - y: %2 - z: %3").arg(m_event->position().x()).arg(m_event->position().y()).arg(m_event->position().z()));
|
||||
m_ui->lblPos->setText(pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShowDetailsDialog::updateMarker()
|
||||
{
|
||||
DEBUG_LOG(m_logger) << "ShowDetailsDialog::updateMarker";
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* FileManagement - Rename Folder Dialog
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Iuliana Ojog, SLSE, 2017-05-22
|
||||
*/
|
||||
|
||||
#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};
|
||||
|
||||
// everything from replay app:
|
||||
QPointer<LtsSession::LtsSession> m_replayAppSession;
|
||||
// end
|
||||
|
||||
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;
|
||||
};
|
||||
} // namespace Timeline
|
||||
@@ -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"><Event Type></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><html><head/><body><p>Plays the audio and/or video clip assoociated to the event in the replay application, in a audio/video dialog.</p></body></html></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><html><head/><body><p>Sets the replay application back to the time the event occured and focuses the event on the map. </p></body></html></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"><font color='#aebac6'>Debug:</font></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,167 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* GUI Plugin for ExerciseManangement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#include "EventFilter/FilterWindow.h"
|
||||
#include "tln_view_gui_plugin.h"
|
||||
#include "tln_dialog.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <stdlib.h> // for abort
|
||||
|
||||
#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->getDtc<InfrastructureManagement::DataInterface>(m_ismDtc))
|
||||
// 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)) // to start the replay situation app
|
||||
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_ismDtc = 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"); // TODO: oder Events?
|
||||
}
|
||||
|
||||
|
||||
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 = /*isMain ? LtsWidgets::ButtonCombination::SeamlessDialog : */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);
|
||||
}
|
||||
|
||||
} // namespace Timeline
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* Gui Plugin for ExerciseManangement
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
*
|
||||
* Created by Mike Wille, SLSE, 2017-02-10
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Plugins/Timeline/tln_view_gui_plugin_interface.h>
|
||||
#include <Plugins/Timeline/tln_data_plugin_interface.h> // forward decls for dtc/ftc
|
||||
#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);
|
||||
|
||||
// dtc's
|
||||
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<InfrastructureManagement::Interface::Dtc> m_ismDtc;
|
||||
std::shared_ptr<AudioVideoManagement::DataInterface> m_avmDataIfc;
|
||||
|
||||
// foreign gui's
|
||||
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;
|
||||
};
|
||||
|
||||
} // namespace Timeline
|
||||
Reference in new issue
Block a user