Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+28
View File
@@ -0,0 +1,28 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Astrid Mueller, SGAS, 2017-08-09
#
ADD_SUBDIRECTORY(Data)
ADD_SUBDIRECTORY(Gui)
#
# Data Plugin Interface
#
ADD_INTERFACE_LIBRARY(CesDataPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ces_data_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
DataPluginInterface
svcCesCommon
)
#
# Gui Plugin Interface
#
ADD_INTERFACE_LIBRARY(CesParticipantGuiPluginInterface
${CMAKE_CURRENT_SOURCE_DIR}/ces_gui_plugin_interface.h
${CMAKE_CURRENT_SOURCE_DIR}/..
GuiPluginInterface
)
+19
View File
@@ -0,0 +1,19 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Astrid Mueller, SGAS, 2017-08-09
#
#
# Data Plugin
#
NGL_ADD_LIBRARY(WS CesDataPlugin MODULE ces_data_plugin.cpp ces_data_plugin.h)
NGL_TARGET_LINK_LIBRARIES(CesDataPlugin
Qt5::Core
CesDataPluginInterface
svcCesClient
NGLLogger
LtsSessionDataDds
)
NGL_INSTALL_TARGET(CesDataPlugin)
@@ -0,0 +1,38 @@
/**
* @RDE_HEADER@
* Data Plugin for CentralEffectSimulation
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-08-09
*/
#include "ces_data_plugin.h"
#include <DDS/DDSConnector/dds_connector.h>
#include <LtsSession/lts_session_data_dds.h>
namespace CentralEffectSimulation
{
std::shared_ptr<DataPluginBase::Interface> DataPlugin::createDataInterface(LtsSession::LtsSessionDataDds *session)
{
std::shared_ptr<Interface::Dtc> dtc;
std::shared_ptr<Interface::Ftc> ftc;
if (!session->createTopicClient(dtc, ftc))
return std::shared_ptr<DataPluginBase::Interface>();
return std::make_shared<DataInterfaceImpl>(dtc, ftc);
}
DataInterfaceImpl::DataInterfaceImpl(const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &dtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Ftc> &ftc)
: DataInterface()
, m_dtc(dtc)
, m_ftc(ftc)
{}
} // namespace CentralEffectSimulation
+54
View File
@@ -0,0 +1,54 @@
/**
* @RDE_HEADER@
* Data Plugin for CentralEffectSimulation
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-08-09
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
namespace CentralEffectSimulation
{
class DataPlugin final : public QObject, public DataPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "data:3:ces")
Q_INTERFACES(DataPluginBase::Plugin)
Q_OBJECT
public:
DataPlugin() = default;
~DataPlugin() = default;
QString pluginName() const override { return QStringLiteral("CentralEffectSimulation"); }
std::shared_ptr<DataPluginBase::Interface> createDataInterface(LtsSession::LtsSessionDataDds *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return partition == IDL::PartitionType::Exercise ||
partition == IDL::PartitionType::Replay ||
partition == IDL::PartitionType::Global;
}
};
class DataInterfaceImpl final : public DataInterface
{
public:
DataInterfaceImpl(const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &dtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Ftc> &ftc);
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> getDtc() override { return m_dtc; }
std::shared_ptr<CentralEffectSimulation::Interface::Ftc> getFtc() override { return m_ftc; }
private:
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_dtc;
std::shared_ptr<CentralEffectSimulation::Interface::Ftc> m_ftc;
};
} // namespace CentralEffectSimulation
+9
View File
@@ -0,0 +1,9 @@
#
# $Id$
# $HeadURL$
# $Author$
#
#ADD_SUBDIRECTORY(Common)
ADD_SUBDIRECTORY(ParticipantMove)
ADD_SUBDIRECTORY(ParticipantUAS)
@@ -0,0 +1,51 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Hannes Baeuerle, SLSE, 2017-02-24
#
SET(ces_participant_move_gui_SRCS
logger.cpp
logger.h
ces_participant_move_gui_plugin.h
ces_participant_move_gui_plugin.cpp
participants_move_model.h
participants_move_model.cpp
participants_move_dialog.h
participants_move_dialog.cpp
participant_move_dialog.h
participant_move_dialog.cpp
)
NGL_WRAP_UI (ces_participant_move_gui_SRCS
participants_move_dialog.ui
participant_move_dialog.ui
)
NGL_ADD_LIBRARY(WS CesParticipantMoveGuiPlugin MODULE ${ces_participant_move_gui_SRCS})
NGL_TARGET_LINK_LIBRARIES(CesParticipantMoveGuiPlugin
AsbDataPluginInterface
LtsCoordTrans
LtsPrinting
PpmDataPluginInterface
PpmGuiParticipantsPluginInterface
CesDataPluginInterface
GuiPluginInterface
AsmGuiPluginInterface
ExmDataPluginInterface
Qt5::Widgets
PpmCommon
FlmDataPluginInterface
LtsUtilsGuiDds
LtsWidgets
LtsSession
LtsSessionData
LtsDataView
SituationMapGuiPluginInterface
LtsUtilsGuiDds
ltsCoordWidget
LtsUtilsSettings
)
NGL_INSTALL_TARGET(CesParticipantMoveGuiPlugin)
@@ -0,0 +1,76 @@
/**
* @RDE_HEADER@
* Gui Plugin for Simulated Movement
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2017-12-19
*/
#include "ces_participant_move_gui_plugin.h"
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Services/CentralEffectSimulation/ces_operator_rights.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
#include "participants_move_dialog.h"
#include <LtsSession/lts_session.h>
namespace CentralEffectSimulation
{
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("Plugins.Gui.Ces.ParticipantMove"))
{
}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<CentralEffectSimulation::DataInterface>(m_cesDtc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
return false;
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_ppmDtc = nullptr;
m_ppmFtc = nullptr;
m_cesDtc = nullptr;
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsWidgets::PluginData plData;
if (!m_session->isReplayPartition())
{
plData.menuGroup = menuGroup();
plData.menuText = tr("Move Participants");
plData.menuIcon = QIcon(QLatin1String("icon:define_movement_simulation.svg"));
plData.identifier = QLatin1String("ParticipantMove");
plData.operatorRight = OperatorRights::ParticipantMove;
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.createWidgetFunc = [this](QWidget * parent)
{
return LtsWidgets::initDialog(new ParticipantsMoveDialog(menuGroup(), parent),
m_session, m_ppmDtc, m_cesDtc, m_ppmFtc);
};
ret.append(plData);
}
return ret;
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,63 @@
/**
* @RDE_HEADER@
* Gui Plugin for Simulated Movement
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2017-12-19
*/
#pragma once
#include "logger.h"
#include <PluginInterfaces/gui_plugin_interface.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <CentralEffectSimulation/ces_dtc.h>
namespace ParticipantManagement
{
class ForeignGuiComboboxInterface;
}
namespace CentralEffectSimulation
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ces.participantmove")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QLatin1String("CesParticipantMoveGui"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override { return tr("Participants");}
QVector<LtsWidgets::PluginData> getActions() override;
private: // attributes
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace CentralEffectSimulation
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "CES.";
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();
}
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for CentralEffectSimulation
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace CentralEffectSimulation
{
typedef NGL::INGLLogger &LOGGER_T;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,538 @@
/**
* @RDE_HEADER@
* Dialog for Simulated Movement
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02 */
#include "participant_move_dialog.h"
#include "ui_participant_move_dialog.h"
#include <PluginInterfaces/gui_plugin_interface.h>
#include <LtsSession/lts_session_data.h>
#include <LtsWidgets/lts_message_dialog.h>
#include <Common/LtsCoordTrans/lts_coord_widget.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
#include "logger.h"
#include <ParticipantManagement/ppm_translation.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <FileManagement/flm_translation.h>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
namespace CentralEffectSimulation
{
static constexpr double s_msConversion = 3.6; // = 3.6 Convert from [km/h] to [m/s]
static constexpr int s_timeMilliConversion = 1000; // 1000 Convert from [s] to [ms]
ParticipantMoveDialog::ParticipantMoveDialog(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_ftc(nullptr)
, m_sitMapGuiIfc(nullptr)
, m_ui(new Ui::WaypointsEdit)
, m_id(0)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_polyline(QPolygonF())
, m_logger(getLogger("ParticipantMoveDialog"))
{
m_ui->setupUi(this);
m_ui->cbJump->hide();
m_ui->label_5->hide();
m_ui->spSpeed->setValue(30); // 30km/h per default
m_ui->lePrefix->setText(tr("Waypoint"));
m_uiRequirements->addRequirement({m_ui->lblMoveStart, [this]() { return hasValidEffectStart(m_ui->dteStartTime); }, tr("Begin time is smaller than current time")});
connect (this, &ParticipantMoveDialog::signalFocused, this, &ParticipantMoveDialog::onFocus);
setOnlineHelpFilename(QStringLiteral("Situation-Move_Participant_0"));
} // end of ctor()
//-----------------------------------------------------------------------------
ParticipantMoveDialog::~ParticipantMoveDialog()
{
m_sitMapGuiIfc = nullptr;
delete m_ui;
emit closeDialog(m_participantData.id());
} // end of dtor()
//-----------------------------------------------------------------------------
void ParticipantMoveDialog::enableUiElements(bool enable)
{
m_ui->pbPosition->setEnabled(enable);
m_ui->pbClear->setEnabled(enable);
} // end of enableUiElements()
//-----------------------------------------------------------------------------
bool ParticipantMoveDialog::init(LtsSession::LtsSessionDataDds *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &cesDtc,
const ParticipantManagement::ParticipantData &data)
{
m_session = session;
m_participantData = data;
m_cesDtc = cesDtc;
//bool editable = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::BorderlinesEdit);
//bool readable = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::BorderlinesShow);
//if (!readable && !editable)
// return false;
if (!m_session->getFtc<CentralEffectSimulation::DataInterface>(m_ftc))
return false;
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
if (m_sitMapGuiIfc)
{
connect(m_ui->pbPosition, &QPushButton::clicked, this, &ParticipantMoveDialog::onGetPolyline);
connect(m_ui->pbClear, &QPushButton::clicked, this, &ParticipantMoveDialog::clearCoordinates);
}
else
{
m_ui->pbPosition->setEnabled(false);
m_ui->pbClear->setEnabled(false);
}
m_ui->dteStartTime->setMinimumTimeMSec(m_session->partitionTime());
m_ui->dteStartTime->setRetrieveCurrentTimeCallback([this]() { return m_session->partitionTime(); });
m_ui->lbIdentifier->setText(QString::fromStdString(data.tacticalIdentifier()));
QString partyStr = ParticipantManagement::trPartyName(ppmDtc->party(m_participantData.partyId()).name());
m_ui->lbParty->setText(partyStr);
QString typeStr = ParticipantManagement::trTypeName(ppmDtc->type(m_participantData.typeId()).name());
m_ui->lbType->setText(typeStr);
// enableUiElements(editable && readable);
enableUiElements(true);
initTableHeader();
connect(cesDtc.get(), &CentralEffectSimulation::Interface::Dtc::simulatedMovementChanged,
this, &ParticipantMoveDialog::onSimulatedMovementChanged);
// Get data for all SimulatedMovements
{
auto sm = [this](const CentralEffectSimulation::SimulatedMovement & sme)
{
onSimulatedMovementChanged(sme, DataModification::eAdded);
};
if (!m_cesDtc->simulatedMovements(sm))
return false;
}
// Save/Load from Library Button
m_buttonBox->connectLibraryButton(this,
&ParticipantMoveDialog::onImportButtonClicked,
&ParticipantMoveDialog::onExportButtonClicked);
if (!m_session->getForeignGuiInterface<FileManagement::ForeignGuiInterface>(m_flmGui))
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Library, false);
return true;
} // end of init()
void ParticipantMoveDialog::onSimulatedMovementChanged(const CentralEffectSimulation::SimulatedMovement &data, DataModification modType)
{
if (modType == DataModification::eRemoved || m_participantData.id() != data.participantId())
return;
INFO_LOG(m_logger) << "onSimulatedMovementChanged";
// Clear data
clearContent();
// set new Content
m_id = data.id();
m_ui->lePrefix->setText(QString::fromStdString(data.name()));
m_ui->cbRepeat->setChecked(data.repeat());
m_ui->cbJump->setChecked(data.jumpToStart());
m_ui->dteStartTime->setMsecsSinceEpoch(data.startTime());
m_polyline.clear();
// Insert data to Vector
for (const SimulatedMovementSegment &segment : data.segments())
{
const Core::GeoPosition2D &pointDds = segment.position();
insertPos(pointDds.lon(), pointDds.lat(), QString::fromStdString(segment.name()), segment.delay(), segment.speed());
m_polyline.push_back(QPointF(pointDds.lon(), pointDds.lat()));
}
// Insert data to Map (Preview)
if (this->amIFocused())
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
}
void ParticipantMoveDialog::showPreview(bool show)
{
if (m_sitMapGuiIfc)
{
if (show)
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
else
m_sitMapGuiIfc->removePreviewObject();
}
}
void ParticipantMoveDialog::onSimulatedMovementRemoveReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error())
{
m_sitMapGuiIfc->cancelActiveRubberbands();
m_sitMapGuiIfc->removePreviewObject();
}
}
void ParticipantMoveDialog::onSimulatedMovementModifyReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error())
m_sitMapGuiIfc->removePreviewObject();
}
void ParticipantMoveDialog::retranslate()
{
translate(m_ui, QString::fromStdString(m_participantData.tacticalIdentifier()), false, tr("Waypoints")); // TODO: lock topic?
DEBUG_LOG(m_logger) << "retranslate";
}
void ParticipantMoveDialog::initTableHeader()
{
QStringList headers;
headers << tr("Identifier") << tr("Idle Time [s]") << tr("Speed [km/h]") << tr("Position");
m_ui->tableWidget->setHorizontalHeaderLabels(headers);
m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
}
// idleTime in [s] speed in [m/s]
void ParticipantMoveDialog::insertPos(const double lon, const double lat, const QString &identifier, const int idleTime, const double speed)
{
QLineEdit *le = new QLineEdit;
QSpinBox *sbDelay = new QSpinBox;
QSpinBox *sbSpeed = new QSpinBox;
sbDelay->setMinimum(m_ui->spIdleTime->minimum());
sbDelay->setMaximum(m_ui->spIdleTime->maximum());
sbSpeed->setMinimum(m_ui->spSpeed->minimum());
sbSpeed->setMaximum(m_ui->spSpeed->maximum());
int rowCount = m_ui->tableWidget->rowCount();
LtsCoordWidget::LtsCoordWidget *wdg = new LtsCoordWidget::LtsCoordWidget();
//wdg->setCoordinate( 8.794556, 53.080827);
wdg->setCoordinate(lon, lat);
wdg->setObjectName(QStringLiteral("positionEdit_") + QString::number(rowCount));
m_ui->tableWidget->insertRow(rowCount);
le->setText(identifier);
m_ui->tableWidget->setCellWidget(rowCount, Name, le);
sbDelay->setValue(idleTime / s_timeMilliConversion);
m_ui->tableWidget->setCellWidget(rowCount, IdleTime, sbDelay);
sbSpeed->setValue(speed * s_msConversion);
m_ui->tableWidget->setCellWidget(rowCount, Speed, sbSpeed);
m_ui->tableWidget->setCellWidget(rowCount, Position, wdg);
wdg->setDisplayType(LtsCoordWidget::LtsCoordWidget::DisplayType::MGRS);
}
//-----------------------------------------------------------------------------
/*
void WaypointsEdit::setData(const Borderline &borderline, bool copy)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << "borderlineId: " << borderline.id()
<< " operatorId: " << borderline.operatorId();
} // end of setData()
*/
//-----------------------------------------------------------------------------
void ParticipantMoveDialog::clearContent()
{
m_ui->lePrefix->clear();
m_ui->cbRepeat->setChecked(false);
m_ui->cbJump->setChecked(false);
clearCoordinates();
}
void ParticipantMoveDialog::clearCoordinates()
{
if (m_ui)
{
m_ui->tableWidget->clearContents();
m_ui->tableWidget->setRowCount(0);
}
// remove PreviewObject:
if ( m_sitMapGuiIfc && this->amIFocused())
m_sitMapGuiIfc->removePreviewObject();
}
void ParticipantMoveDialog::onFocus()
{
showPreview(true);
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
}
void ParticipantMoveDialog::onGetPolyline()
{
DEBUG_LOG(m_logger) << LOGFUNCTION;
if (!m_sitMapGuiIfc)
return;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return;
}
QPolygonF coordinates;
int i = 0;
while (true)
{
LtsCoordWidget::LtsCoordWidget *w = findChild<LtsCoordWidget::LtsCoordWidget *>(QStringLiteral("positionEdit_%1").arg(i));
if (!w)
break;
if (!w->coordinate().isNull())
coordinates << w->coordinate();
++i;
}
m_sitMapGuiIfc->getPolyline(this,
SLOT(onPolylineData(QPolygonF)),
nullptr,
2,
11,
-1,
-1,
coordinates);
} // end of onGetPolyline()
//-----------------------------------------------------------------------------
void ParticipantMoveDialog::onPolylineData(const QPolygonF &polyline)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " numberOfPoints: " << polyline.size();
if (polyline.size() < 2)
return;
m_polyline = polyline;
clearCoordinates();
for (int i = 0; i < polyline.size(); i++)
insertPos(polyline.at(i).x(), polyline.at(i).y(),
m_ui->lePrefix->text() + QLatin1Char('_') + QString::number(i + 1),
m_ui->spIdleTime->value() * s_timeMilliConversion,
m_ui->spSpeed->value() / s_msConversion);
// create PreviewObject:
m_sitMapGuiIfc->displayPreviewObject(this, polyline, false);
} // end of onPolylineData()
//-----------------------------------------------------------------------------
bool ParticipantMoveDialog::hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const
{
// if there is visible a enabled/disable checkbox -> also allow 0 as effect start
const bool bEmptyAllowed = dte->isCheckable();
const auto ms = dte->msecsSinceEpoch();
// no effect start -> ok
if (bEmptyAllowed && ms == 0)
return true;
return ms > m_session->partitionTime();
}
SimulatedMovement ParticipantMoveDialog::requestContent() const
{
std::string name = m_ui->lePrefix->text().toStdString();
int32_t repeat = m_ui->cbRepeat->isChecked();
//int32_t jumpToStart = m_ui->cbJump->isChecked();
int32_t jumpToStart = true;
rti::core::int64 startTime = m_ui->dteStartTime->msecsSinceEpoch();
int32_t participantId = m_participantData.id();
int32_t nextPoint = 0;
int cntSegments = m_ui->tableWidget->rowCount();
std::vector<CentralEffectSimulation::SimulatedMovementSegment> segments;
segments.resize(cntSegments);
for (int i = 0; i < cntSegments; i++)
{
QWidget *widget = m_ui->tableWidget->cellWidget(i, Name);
const QString nameSeg = static_cast<QLineEdit *>(widget)->text();
segments[i].name(nameSeg.toStdString());
widget = m_ui->tableWidget->cellWidget(i, IdleTime);
const int idleTime = static_cast<QSpinBox *>(widget)->value() * s_timeMilliConversion;
segments[i].delay(idleTime);
widget = m_ui->tableWidget->cellWidget(i, Speed);
const double speed = static_cast<QSpinBox *>(widget)->value() / s_msConversion;
segments[i].speed(speed);
widget = m_ui->tableWidget->cellWidget(i, Position);
const QPointF point = static_cast<LtsCoordWidget::LtsCoordWidget *>(widget)->coordinate();
const Core::GeoPosition2D pos(Core::GeoPosition2D(point.x(), point.y()));
segments[i].position(pos);
}
return SimulatedMovement(m_id,
name,
startTime,
participantId,
segments,
repeat,
jumpToStart,
nextPoint
);
}
bool ParticipantMoveDialog::apply()
{
int cntSegments = m_ui->tableWidget->rowCount();
if (cntSegments > 0)
{
const SimulatedMovement req = requestContent();
INFO_LOG(m_logger) << "--- onApplyMessage() ";
m_requestHelper->addRequest([this, req]()
{
return m_ftc->simulatedMovementModifyRequest(req, this);
});
}
else
{
if (m_id > 0)
{
Core::RemoveElementRequest req(m_id);
m_id = 0; // Next time new Route
INFO_LOG(m_logger) << "--- onApplyMessage() ";
m_requestHelper->addRequest([req, this]()
{
return m_ftc->simulatedMovementRemoveRequest(req, this);
});
}
}
return m_requestHelper->startRequests();
}
//-----------------------------------------------------------------------------
// Save / Load Simulation in DB
//-----------------------------------------------------------------------------
QByteArray ParticipantMoveDialog::simulatedMovementToJson() const
{
const SimulatedMovement req = requestContent();
QJsonObject obj;
obj[QStringLiteral("XmlType")] = FileManagement::toString(FileManagement::XmlType::CESParticipantMove);
obj[QStringLiteral("id")] = req.id();
obj[QStringLiteral("jumpToStart")] = req.jumpToStart();
obj[QStringLiteral("name")] = QString::fromStdString(req.name());
obj[QStringLiteral("nextPoint")] = req.nextPoint();
obj[QStringLiteral("participantId")] = req.participantId();
obj[QStringLiteral("repeat")] = req.repeat();
obj[QStringLiteral("startTime")] = req.startTime();
QJsonArray arr;
for (auto it = req.segments().begin(); it != req.segments().end(); ++it)
{
QJsonObject inner;
inner[QStringLiteral("delay")] = it->delay();
inner[QStringLiteral("name")] = QString::fromStdString(it->name());
inner[QStringLiteral("speed")] = it->speed();
inner[QStringLiteral("lat")] = it->position().lat();
inner[QStringLiteral("lon")] = it->position().lon();
arr += inner;
}
obj[QStringLiteral("segments")] = arr;
QJsonDocument doc(obj);
return doc.toJson(QJsonDocument::Compact);
}
SimulatedMovement ParticipantMoveDialog::jsonToSimulatedMovement(const QByteArray &content) const
{
// already checked that content is not empty, parseable and contains proper XmlType (CESParticipantMove)
CentralEffectSimulation::SimulatedMovement result;
const QJsonDocument doc(QJsonDocument::fromJson(content));
const QJsonObject obj(doc.object());
result.id(obj[QStringLiteral("id")].toInt()); //TODO Library: check id = 0?
result.jumpToStart(obj[QStringLiteral("jumpToStart")].toInt());
result.name(obj[QStringLiteral("name")].toString().toStdString());
result.nextPoint(obj[QStringLiteral("nextPoint")].toInt());
result.participantId(m_participantData.id());
result.repeat(obj[QStringLiteral("repeat")].toInt());
result.startTime(obj[QStringLiteral("startTime")].toDouble());
const QJsonArray arr(obj.value(QStringLiteral("segments")).toArray());
auto &segments = result.segments();
segments.resize(arr.size());
for (int i = 0; i < arr.size(); ++i)
{
CentralEffectSimulation::SimulatedMovementSegment &segment = segments[i];
const QJsonObject objArr(arr.at(i).toObject());
segment.delay(objArr[QStringLiteral("delay")].toDouble());
segment.name(objArr[QStringLiteral("name")].toString().toStdString());
segment.position().lat(objArr[QStringLiteral("lat")].toDouble());
segment.position().lon(objArr[QStringLiteral("lon")].toDouble());
segment.speed(objArr[QStringLiteral("speed")].toDouble());
}
return result;
}
void ParticipantMoveDialog::onExportButtonClicked()
{
QJsonObject saveObject;
saveObject[QStringLiteral("content")] = QString();
const QByteArray byteArray = simulatedMovementToJson();
int fileId = m_flmGui->saveFileContent(this, FileManagement::FileType::Xml, m_session->exerciseId(), byteArray);
if (fileId > 0)
DEBUG_LOG(m_logger) << "Saved file with id = " << fileId;
else
ERROR_LOG(m_logger) << "Could not save file in library ";
}
void ParticipantMoveDialog::onImportButtonClicked()
{
DEBUG_LOG(m_logger) << " onImportButtonClicked() ";
QByteArray content;
int fileId = m_flmGui->loadFileContent(this, content, {FileManagement::FileType::Xml}, m_session->exerciseId(), FileManagement::toString(FileManagement::XmlType::CESParticipantMove));
if (fileId > 0)
{
if (!m_flmGui->isXmlType(content, FileManagement::toString(FileManagement::XmlType::CESParticipantMove)))
{
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
{
SimulatedMovement req = jsonToSimulatedMovement(content);
INFO_LOG(m_logger) << "--- onImportButtonClicked() ";
m_requestHelper->addRequest([this, req]()
{
return m_ftc->simulatedMovementModifyRequest(req, this);
});
m_requestHelper->startRequests();
}
}
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,115 @@
/**
* @RDE_HEADER@
* Dialog for Simulated Movement
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02 */
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <CentralEffectSimulation/ces_ftc.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <QStandardItemModel>
#include <LtsUtilsGuiDds/request_helper.h>
#include <LtsSession/lts_session.h>
//DDS
#include <ParticipantManagement/ppm_dtc.h>
#include <CentralEffectSimulation/ces_dtc.h>
#include "logger.h"
namespace Ui
{
class WaypointsEdit;
}
namespace LtsWidgets
{
class LtsDateTimeEdit;
}
namespace CentralEffectSimulation
{
class TypeModel;
class ParticipantMoveDialog: public LtsWidgets::LtsDialog
, protected CentralEffectSimulation::Interface::Ftc::SimulatedMovementRemoveReplyHandler
, protected CentralEffectSimulation::Interface::Ftc::SimulatedMovementModifyReplyHandler
{
Q_OBJECT
public:
enum SegementColumns
{
Name,
IdleTime,
Speed,
Position
};
explicit ParticipantMoveDialog(QWidget *parent = nullptr);
~ParticipantMoveDialog();
bool init(LtsSession::LtsSessionDataDds *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &cesDtc,
const ParticipantManagement::ParticipantData &data);
void retranslate() override;
//virtual functions from CentralEffectSimulation::Interface::Ftc
void onSimulatedMovementRemoveReply(const Core::FunctionReplyObject &replyObject) override;
void onSimulatedMovementModifyReply(const Core::FunctionReplyObject &replyObject) override;
void showPreview(bool show);
signals:
void closeDialog(int32_t participantId);
private:
//std::vector<LtsCoordWidget::LtsCoordWidget *> coordWidgets() const override;
//void setData(const Borderline &borderline, bool copy);
void enableUiElements(bool enable);
void initTableHeader();
void insertPos(const double lon, const double lat, const QString &identifier, const int idleTime, const double speed);
//void onApply();
void clearCoordinates();
void clearContent();
bool hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const;
bool apply() override;
SimulatedMovement requestContent() const;
QByteArray simulatedMovementToJson() const;
SimulatedMovement jsonToSimulatedMovement(const QByteArray &content) const;
private slots:
void onGetPolyline();
void onPolylineData(const QPolygonF &polyline); // callback for onGetPolyline()
void onSimulatedMovementChanged(const CentralEffectSimulation::SimulatedMovement &data, DataModification modType);
void onFocus();
void onExportButtonClicked();
void onImportButtonClicked();
private:
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
std::shared_ptr<Interface::Ftc> m_ftc;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
Ui::WaypointsEdit *m_ui;
LtsSession::LtsSessionDataDds *m_session;
ParticipantManagement::ParticipantData m_participantData;
int m_id;
LtsUtils::RequestHelper *m_requestHelper;
QPolygonF m_polyline;
LOGGER_T m_logger;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,245 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WaypointsEdit</class>
<widget class="QWidget" name="WaypointsEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>808</width>
<height>535</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">MessagingView</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Tact. Identifier:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lbIdentifier">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Party:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lbParty">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Type:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lbType">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblMoveStart">
<property name="text">
<string>Start Time:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="LtsWidgets::LtsDateTimeEdit" name="dteStartTime">
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Edit Waypoints in Map:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QPushButton" name="pbPosition">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Light/resources/rme_light_style.qrc">
<normaloff>:/style/position.svg</normaloff>:/style/position.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClear">
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset resource="../../../Styles/Light/resources/rme_light_style.qrc">
<normaloff>:/style/remove.svg</normaloff>:/style/remove.svg</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Idle Time [s]:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spIdleTime">
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Prefix:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lePrefix">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxLength">
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Speed [km/h]:</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Repeat:</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Jump to Start</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="cbRepeat">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QCheckBox" name="cbJump">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spSpeed"/>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableWidget">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="columnCount">
<number>4</number>
</property>
<column/>
<column/>
<column/>
<column/>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsDateTimeEdit</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_date_time_edit.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../Styles/Light/resources/rme_light_style.qrc"/>
</resources>
<connections/>
</ui>
@@ -0,0 +1,905 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02*/
#include "participants_move_dialog.h"
#include "participants_move_model.h"
#include "ui_participants_move_dialog.h"
#include <LtsWidgets/lts_column_filter_proxy_model.h>
#include <AdvancedSymbology/asb_data_plugin_interface.h>
#include <CentralEffectSimulation/ces_data_plugin_interface.h>
#include <Plugins/ExerciseManagement/exm_data_plugin_interface.h>
#include <Plugins/AssetManagement/asm_data_plugin_interface.h>
#include <AreaEffectSimulation/aes_data_plugin_interface.h>
#include <LtsUtilsSettings/settings.h>
#include "participant_move_dialog.h"
#include <LtsCoordTrans/lts_coord_trans.h>
#include <LtsSession/lts_session_data_dds.h>
#include <LtsSession/lts_session_data.h>
#include <FilterManagement/flt_participant_plugin_interface.h>
#include <FilterManagement/flt_symbol_appearance_settings.h>
#include <LtsCoordTrans/lts_coord_widget.h>
#include <QInputDialog>
#include <QLabel>
#include <QDoubleSpinBox>
#include <QDialogButtonBox>
#include <QDebug>
namespace CentralEffectSimulation
{
ParticipantsMoveDialog::ParticipantsMoveDialog(const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_participantModel(nullptr)
, m_ppmDtc(nullptr)
, m_ppmCbxIfc(nullptr)
, m_ftc(nullptr)
, m_ui(new Ui::ParticipantMoveDialog)
, m_session(nullptr)
, m_menuGroup(menuGroup)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_sitMapGuiIfc(nullptr)
, m_logger(getLogger("ParticipantsMoveDialog"))
{
m_ui->setupUi(this);
setUnchangeable();
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save, this, &ParticipantsMoveDialog::onSetSimulatedMGRSPosition);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
m_buttonBox->setIcon(LtsWidgets::DialogButton::Save, QIcon(QStringLiteral("icon:position.svg")));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &ParticipantsMoveDialog::onClicked);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &ParticipantsMoveDialog::onSetPosition);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &ParticipantsMoveDialog::onRemove);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
setOnlineHelpFilename(QStringLiteral("Situation-Move_Participant_0"));
}
ParticipantsMoveDialog::~ParticipantsMoveDialog()
{
m_sitMapGuiIfc = nullptr;
delete m_ui;
}
static constexpr int s_maxAngleDeg = 360;
static constexpr int s_maxAngleMil = 6400;
inline constexpr int mil2Deg(const int &mil)
{
return s_maxAngleDeg * mil / s_maxAngleMil;
}
inline constexpr int deg2Mil(const int &angleDeg)
{
return s_maxAngleMil * angleDeg / s_maxAngleDeg;
}
void ParticipantsMoveDialog::retranslate()
{
translate(m_ui, tr("Move Participant"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->setText(tr("Set Simulated MGRS Position"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setText(tr("Set Simulated Position"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Edit Simulation"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Remove)->setText(tr("Remove Simulation"));
}
bool ParticipantsMoveDialog::init(LtsSession::LtsSession *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &cesDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc)
{
m_ppmDtc = ppmDtc;
m_cesDtc = cesDtc;
m_session = session;
m_ppmFtc = ppmFtc;
if (!m_ppmDtc)
return false;
if (!m_ppmFtc)
return false;
if (!session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmCbxIfc))
return false;
if (!m_session->getFtc<CentralEffectSimulation::DataInterface>(m_ftc))
return false;
std::shared_ptr<ExerciseManagement::Interface::Dtc> exmDtc;
if (!m_session->getDtc<ExerciseManagement::DataInterface>(exmDtc))
{
ERROR_LOG(m_logger) << "failed to get exmDtc ";
return false;
}
std::shared_ptr<AssetManagement::Interface::Dtc> asmDtc;
if (!m_session->getDtc<AssetManagement::DataInterface>(asmDtc))
{
ERROR_LOG(m_logger) << "failed to get asmDtc ";
return false;
}
if (asmDtc == nullptr || exmDtc == nullptr)
return false;
const ExerciseManagement::Exercise exc = exmDtc->exercise(m_session->exerciseId());
AssetManagement::TrainingArea ta = asmDtc->trainingArea(exc.trainingAreaId());
if (ta.id() != exc.trainingAreaId())
{
ERROR_LOG(m_logger)<<" couldn't get Training Area with id: "<<exc.trainingAreaId();
return false;
}
if (!m_session ->getDtc<AreaEffectSimulation::DataInterface>(m_aesDtc))
{
ERROR_LOG(m_logger)<<"failed to get aesDtc";
return false;
}
// get training area Rect
const LtsCoordTrans::UtmCoordinate &bottomLeft = LtsCoordTrans::UtmCoordinate::fromGeographic(ta.bottomLeft().lon(), ta.bottomLeft().lat());
m_trainingAreaRect = QRectF(bottomLeft.geographic(0, ta.height()), bottomLeft.geographic(ta.width(), 0));
// for relativeMove of units via SetSimulatedPositionRelative:
m_ppmDtc->enableUnitPosition();
m_ppmDtc->waitForHistoricalDataUnitPosition(1000);
std::shared_ptr<AdvancedSymbology::ForeignDataInterface> asb;
session->getForeignDataInterface<AdvancedSymbology::DataInterface>(asb);
m_participantModel = new ParticipantMoveModel(this, m_ppmDtc, asb);
// only needed to set recursiveFilteringEnabled
auto proxyModel = new ParticipantManagement::ParticipantTreeFilterProxyModel(this);
proxyModel->setSourceModel(m_participantModel);
proxyModel->setRecursiveFilteringEnabled(true);
m_ui->dvParticipants->setModel(proxyModel);
m_ui->dvParticipants->setSortIndicator(0, Qt::AscendingOrder);
connect(m_ui->cbParty,
static_cast<void (LtsWidgets::LtsComboBox::*)(int)>(&LtsWidgets::LtsComboBox::currentIndexChanged),
this, &ParticipantsMoveDialog::changeParty);
connect(m_ui->cbAll, &QCheckBox::toggled, this, &ParticipantsMoveDialog::changeParty);
connect(m_ui->dvParticipants, &LtsDataView::LtsDataView::selectionChanged,
this, &ParticipantsMoveDialog::onSelectionChanged);
connect(m_participantModel, &ParticipantMoveModel::newData,
this, &ParticipantsMoveDialog::onModelChanged);
connect(m_ui->dvParticipants, &LtsDataView::LtsDataView::signalDoubleClicked,
this, &ParticipantsMoveDialog::onDoubleClicked);
m_ppmCbxIfc->fillPartyComboBox(m_ui->cbParty, ParticipantManagement::ForeignGuiComboboxInterface::CbxPartyFilter::All);
changeParty();
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setIcon(QIcon(QStringLiteral("icon:position.svg")));
#ifndef LTS_DEBUG
m_ui->dvParticipants->hideColumn(ParticipantMoveModel::ColParticipantId);
#endif
return true;
}
//private
void ParticipantsMoveDialog::closeDialogReceived(int32_t participantId)
{
m_participantDialogMap.remove(participantId);
}
void ParticipantsMoveDialog::onSelectionChanged()
{
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
bool isOne = (indexList.size() == 1);
// Set remove Btn
if (!isOne)
return;
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
DEBUG_LOG(m_logger) << "ParticipantId: " << data.id();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, data.isSimulated());
// Show preview of selected Simulation
if (data.isSimulated() && m_participantDialogMap.contains(data.id()))
m_participantDialogMap.value(data.id())->showPreview(true);
else
{
// Remove Preview
QMapIterator<int, ParticipantMoveDialog *> i(m_participantDialogMap);
while (i.hasNext())
{
i.next();
//cout << i.key() << ": " << i.value() << endl;
i.value()->showPreview(false);
}
}
// allow moving units (with all its children)
{
bool isParticipantInUseOrAdler = participantInUse4ExplosionCluster(indexList.first());
// Check for Adler Type too
if (!isParticipantInUseOrAdler)
isParticipantInUseOrAdler = (m_ppmDtc->isAdlerType(data.typeId()) && !data.name().empty());
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, isOne && !isParticipantInUseOrAdler);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, isOne && !isParticipantInUseOrAdler);
}
if (m_ppmDtc->type(data.typeId()).typeClass() != ParticipantManagement::TypeClass_def::Unit)
{
if (!data.equipmentNumber().is_set() || data.equipmentNumber().get() <= 0)
{
//No Sim MoveMent for Adler SAA Participants
isOne &= !(m_ppmDtc->isAdlerType(data.typeId()) && !data.name().empty());
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
}
else
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
}
}
void ParticipantsMoveDialog::onModelChanged()
{
m_ui->dvParticipants->expandAll();
DEBUG_LOG(m_logger) << "onModelChanged";
}
void ParticipantsMoveDialog::onDoubleClicked()
{
if (!m_sitMapGuiIfc)
return;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return;
}
if (!m_buttonBox->isButtonEnabled(LtsWidgets::DialogButton::Edit))
return;
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
bool isOne = (indexList.size() == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
if (!isOne)
return;
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
DEBUG_LOG(m_logger) << "ParticipantId: " << data.id();
if (!m_participantDialogMap.contains(data.id()))
{
ParticipantMoveDialog *dialog = new ParticipantMoveDialog(this);
m_participantDialogMap.insert(data.id(), dialog);
connect(dialog, &ParticipantMoveDialog::closeDialog,
this, &ParticipantsMoveDialog::closeDialogReceived);
addDialog(LtsWidgets::initDialog(dialog, m_session, m_ppmDtc, m_cesDtc, data),
m_menuGroup, QStringLiteral("cesNewSimulation%1").arg(data.id()), LtsWidgets::LayoutArea::eDialogTab);
}
else
focusDialog(m_menuGroup, QStringLiteral("cesNewSimulation%1").arg(data.id()), LtsWidgets::LayoutArea::eDialogTab);
}
//Slots
void ParticipantsMoveDialog::changeParty()
{
if (m_ui->cbAll->isChecked())
{
m_ui->cbParty->setEnabled(false);
m_ui->dvParticipants->setEnabled(false);
m_participantModel->resetModel();
}
else
{
m_ui->cbParty->setEnabled(true);
m_ui->dvParticipants->setEnabled(true);
int partyId = m_ui->cbParty->currentData().toInt();
m_participantModel->onReinitModel(partyId);
m_ui->dvParticipants->expandAll();
}
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, m_ui->cbAll->isChecked());
}
void ParticipantsMoveDialog::onClicked()
{
onDoubleClicked();
}
void ParticipantsMoveDialog::onRemove()
{
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
bool isOne = (indexList.size() == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
if (!isOne)
return;
const ParticipantManagement::ParticipantData data(participantFromIndex(indexList.first()));
INFO_LOG(m_logger) << "onRemove ParticipantId: " << data.id();
// Remove (possible) open Dialogs
delete m_participantDialogMap.value(data.id());
m_participantDialogMap.remove(data.id());
removeFtc(data.id());
}
void ParticipantsMoveDialog::onSetSimulatedMGRSPosition()
{
const QModelIndexList &indexList = m_ui->dvParticipants->selectedRows();
if (indexList.size() == 1)
{
QPointF mgrsCoordinate;
m_mgrsPosEditCoordinateActive = true;
if(!participantInUse4ExplosionCluster(indexList.first()))
{
onGetCoordinate(mgrsCoordinate);
m_mgrsPosEditCoordinateActive = false;
}
else
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This Participant Unit is currently in use.\nThe Parameters can't be changed!"));
}
}
bool ParticipantsMoveDialog::participantInUse4ExplosionCluster(const QModelIndex &participantIndex)
{
const ParticipantManagement::ParticipantData participantData(participantFromIndex(participantIndex));
bool bret=false;
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
bool isUnitType = (participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
// get parent
//only units tell us if participants are in used with explosion cluster
if (!isUnitType)
{
const QModelIndex parentIndex = m_participantModel->indexFromParticipantId(participantData.superiorModId());
const ParticipantManagement::ParticipantData parentParticipantData(participantFromIndex(parentIndex));
const ParticipantManagement::Type &partentParticipantType = m_ppmDtc->type(parentParticipantData.typeId());
isUnitType = (partentParticipantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
(partentParticipantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
bret = isUnitType && isParticipantInUseForExplosionCluster(parentParticipantData.id());;
}
else
bret = isParticipantInUseForExplosionCluster(participantData.id());
return bret;
}
void ParticipantsMoveDialog::onSimulatedMovementRemoveByParticipantIdReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void ParticipantsMoveDialog::onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void ParticipantsMoveDialog::onSetSimulatedPositionRelativeReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void ParticipantsMoveDialog::onSetSimulatedParticipantFormationReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
bool ParticipantsMoveDialog::removeFtc(int32_t participantId)
{
if (participantId <= 0)
return true;
CentralEffectSimulation::SimulatedMovementRemoveByParticipantId req(participantId);
m_requestHelper->addRequest([req, this]()
{
return m_ftc->simulatedMovementRemoveByParticipantIdRequest(req, this);
});
return m_requestHelper->startRequests();
}
void ParticipantsMoveDialog::onGetCoordinate(QPointF coordinate)
{
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
if (indexList.size() == 0)
return;
const ParticipantManagement::ParticipantData participantData(participantFromIndex(indexList.first()));
INFO_LOG(m_logger) << LOGFUNCTION << "ParticipantId=" << participantData.id()
<< " EquipmentNr=" << participantData.equipmentNumber()
<< " onGetCoordinate x=" << coordinate.x() << " y=" << coordinate.y();
if (participantData.id() <= 0)
return;
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
const bool &isUnitType =
(participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
// get participant type properties
// special handling when participant has Artillery as property
m_formationProps.setFormation(QString::fromStdString(participantType.properties()));
const bool &withFormation = (isUnitType && m_formationProps.isArtillery);
if (withFormation || m_mgrsPosEditCoordinateActive)
setFormationAndPositioningUi(participantData, coordinate, withFormation);
else if (isUnitType)
m_shiftModifierWhileOnSetPosition ? doSetSimulatedPositionRequest(participantData, coordinate) :
doSetSimulatedPositionRelativeRequest(participantData, coordinate);
else
doSetSimulatedPositionRequest(participantData, coordinate); // single (human|vehicle)
}
void ParticipantsMoveDialog::onSetPosition()
{
if (!m_sitMapGuiIfc) //sanity
return;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return;
}
if (!m_ui->cbAll->isChecked())
{
const QModelIndexList indexList = m_ui->dvParticipants->selectedRows();
bool isOne = (indexList.size() == 1);
if (!isOne)
return;
//const ParticipantManagement::ParticipantData participantData(participantFromIndex(indexList.first()));
if (participantInUse4ExplosionCluster(indexList.first()))
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("This Participant Unit is currently in use.\nThe Parameters can't be changed!"));
return;
}
}
m_shiftModifierWhileOnSetPosition = QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier);
m_sitMapGuiIfc->getCoordinate(this, SLOT(onGetCoordinate(QPointF)), nullptr);
}
void ParticipantsMoveDialog::setDialogEnable(bool enable)
{
m_ui->dvParticipants->setEnabled(enable);
m_ui->cbParty->setEnabled(enable);
m_ui->cbAll->setEnabled(enable);
m_buttonBox->setEnabled(enable);
}
bool ParticipantsMoveDialog::isParticipantInUseForExplosionCluster(int id)
{
if (!m_aesDtc)
{
ERROR_LOG(m_logger)<<" m_aesDTC is not setted";
return true;
}
const QMap<qint32, AreaEffectSimulation::ExplosionCluster> &ecMap = m_aesDtc->explosionClusters();
for(const AreaEffectSimulation::ExplosionCluster &aes : qAsConst(ecMap))
{
if (aes.participantId() == id &&
(aes.effectStateId() == AreaEffectSimulation::AesEffectState::EsPrepared ||
aes.effectStateId() == AreaEffectSimulation::AesEffectState::EsActivated))
return true;
}
return false;
}
void ParticipantsMoveDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->dvParticipants->setColumnsOrganiserEnabled(identifier(), true);
}
/*!
* \brief ParticipantsMoveDialog::setFormationAndPositioningUi
* \param withMgrsPos:
* \param withFormation
* \param mgrsCoordinate
* \return
*/
void ParticipantsMoveDialog::setFormationAndPositioningUi(const ParticipantManagement::ParticipantData &participantData,
QPointF &mgrsCoordinate,
const bool &unitWithFormation)
{
if (!unitWithFormation && !m_mgrsPosEditCoordinateActive)
return;
const ParticipantManagement::Type &participantType = m_ppmDtc->type(participantData.typeId());
const bool isUnitType =
(participantType.typeClass() == ParticipantManagement::TypeClass::Unit) ||
(participantType.typeClass() == ParticipantManagement::TypeClass::SupportUnit);
m_formationProps.setFormation(QString::fromStdString(participantType.properties()));
if (m_formationProps.hasFormationData())
return;
LtsWidgets::LtsFramelessDialog *dialog = new LtsWidgets::LtsFramelessDialog(this, LtsWidgets::Behaviour::Popup);
dialog->setFixedSize(390, 300);
dialog->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
int row = 0;
QGridLayout *gla = new QGridLayout(dialog);
// Message Infobox
{
QLabel *msgLbl = new QLabel(tr("<b> Following Parameter(s) must be set to proceed. </b>"), dialog);
msgLbl->setWordWrap(true);
gla->addWidget(msgLbl, row, 0, 1, 2);
}
// set mgrs Postion edit
LtsCoordWidget::LtsCoordWidget *posEdit = new LtsCoordWidget::LtsCoordWidget(LtsCoordWidget::LtsCoordWidget::DisplayType::MGRS, dialog);
{
QLabel *posEditLbl = new QLabel(tr("MGRS Position:"), dialog);
LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance();
const QSize offset = QSize(ps->value(QStringLiteral("MgrsSquaresOffsets"), QStringLiteral("xOffset")).toInt(),
ps->value(QStringLiteral("MgrsSquaresOffsets"), QStringLiteral("yOffset")).toInt());
posEdit->setWithSurroundingMgrsSquares(true);
posEdit->setMgrsSquareEditable(true);
QVector<LtsCoordTrans::UtmCoordinate> geoCoords;
if (LtsCoordTrans::defaultMgrsSquareWithOffsets().isEmpty())
{
const QRectF &trainingAreaWithMargin = LtsCoordTrans::addMarginToArea(m_trainingAreaRect, offset);
geoCoords = LtsCoordTrans::getMgrsSquares(trainingAreaWithMargin,false,false,true);
}
else
geoCoords = LtsCoordTrans::defaultMgrsSquareWithOffsets();
posEdit->setMgrsSquares(geoCoords);
if (!mgrsCoordinate.isNull())
posEdit->setCoordinate(mgrsCoordinate, true);
++row;
gla->addWidget(posEditLbl, row, 0, 1, 1);
gla->addWidget(posEdit, row, 1, 1, 1);
QFrame *line = new QFrame(dialog);
line->setObjectName(QString::fromUtf8("line"));
line->setGeometry(QRect(110, 110, 118, 3));
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
++row;
gla->addWidget(line, row, 0, 1, 2);
}
// set Angle
QSpinBox *angleSBox = nullptr;
//if (m_formationProps.angle == -1 && unitWithFormation)
{
QLabel *angleLbl = new QLabel( tr("Angle:"), dialog); // Grundrichtung
angleSBox = new QSpinBox(dialog);
angleSBox->setMinimum(0);
angleSBox->setMaximum(s_maxAngleMil);
angleSBox->setSuffix(tr(" mil"));
++row;
gla->addWidget(angleLbl, row, 0, 1, 1);
gla->addWidget(angleSBox, row, 1, 1, 1);
}// end setting angle
// set Distance
QSpinBox *distanceSBox = nullptr;
QComboBox *distanceCBox = nullptr;
{
QLabel *distanceLbl = new QLabel(tr("Distance:"), dialog);
distanceCBox = new QComboBox(dialog);
for(const auto &dis : m_formationProps.distanceSets.toStdMap())
{
QString str;
if (dis.first == QStringLiteral("Locked")) // Geschlossen
str = tr("Locked");
else if (dis.first == QStringLiteral("Unlocked")) // Aufgelockert
str = tr("Unlocked");
distanceCBox->addItem(QStringLiteral("%1 (%2m)").arg(str).arg(dis.second.toInt()), dis.second.toInt());
}
++row;
gla->addWidget(distanceLbl, row, 0, 1, 1);
gla->addWidget(distanceCBox, row, 1, 1, 1);
}
// Vertical spacer
{
QScopedPointer<QSpacerItem> verticalSpacer(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding));
row++;
gla->addItem(verticalSpacer.take(), row, 0, 1, 1);
}
// dialog button
LtsWidgets::LtsDialogButtonBox *btnBox = new LtsWidgets::LtsDialogButtonBox(dialog);
btnBox->getButton(LtsWidgets::DialogButton::Ok)->setText(tr("Apply"));
btnBox->getButton(LtsWidgets::DialogButton::Close)->setText(tr("Abort"));
// horizontal spacer
{
QScopedPointer <QSpacerItem> horizontalSpacer(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
row++;
gla->addItem(horizontalSpacer.take(), row, 0, 1, 1);
gla->addWidget(btnBox, row, 0, 1, 2);
}
// handle Data
auto applyData = [=]()
{
// angle can be get in ° or mil, but we work with angle in degree. so we habe to convert mil value if defined
// 0° orientation is east ouest
{ // get angle value
int angleMil = angleSBox->value();
// angle in mil: convert in degree, then we work in degree
m_formationProps.angle = std::fmod((mil2Deg(angleMil) + 90), 360);// 0° ost-west gerichtet
DEBUG_LOG(m_logger)<<" angle in deg mil: "<<angleMil
<<" -> degree: "<< mil2Deg(angleMil)<<" final position(°): "<<m_formationProps.angle;
}
{// get distance value
// spinbox is enable when there is no distance sets available. The user will enter a desired distance
if (distanceSBox != nullptr)
m_formationProps.distance = distanceSBox->value();
else if(distanceCBox != nullptr)
m_formationProps.distance = distanceCBox->currentData().toInt();
}
const QPointF mgrsCoordinate = posEdit->coordinate();
if (mgrsCoordinate.isNull())
{
WARNING_LOG(m_logger)<<"MGRS Coordinates invalid!";
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Coordinates invalid!\nPlease check them and try again."));
return;
}
if (unitWithFormation && (m_formationProps.hasFormationData() || !mgrsCoordinate.isNull()))
{
doSetSimulatedParticipantFormationRequest(participantData, mgrsCoordinate, m_formationProps.getFormationDataObjectString());
}
else if (isUnitType)
{
// set while user is pressing
m_shiftModifierWhileOnSetPosition ? doSetSimulatedPositionRequest(participantData, mgrsCoordinate) :
doSetSimulatedPositionRelativeRequest(participantData, mgrsCoordinate);
}
else
doSetSimulatedPositionRequest(participantData, mgrsCoordinate); // single (human|vehicle)
setDialogEnable(true);
dialog->accept();
};
// abort/close
connect(btnBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, dialog, [=](){
setDialogEnable(true);
dialog->accept();
});
// apply
connect(btnBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, applyData);
dialog->setLayout(gla);
dialog->show();
setDialogEnable(false);
}
bool ParticipantsMoveDialog::getUnitPosition(int32_t participantId, Core::GeoPosition &unitPositionOut)
{
// flt
std::shared_ptr<FilterManagement::ForeignFltParticipantGuiInterface> fltParticipantIfc;
m_session->getForeignGuiInterface<FilterManagement::ForeignFltParticipantGuiInterface>(fltParticipantIfc); // not in global
if (!fltParticipantIfc)
return false;
int operatorId = LtsSessionData::LtsSessionData::getInstance()->getOperatorId();
QString workspaceId = m_session->workspaceId();
std::shared_ptr<FilterManagement::SymbolAppearanceSettings> symbolAppearanceSettings =
fltParticipantIfc->symbolAppearanceForOperator(operatorId, workspaceId);
FilterManagement::SymbolAppearanceSettings::Settings settings =
symbolAppearanceSettings->settings();
FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition usp =
settings.symbolSettings.unitSymbolPosition;
ParticipantManagement::UnitPosition up = m_ppmDtc->unitPosition(participantId);
if (up.participantId() != participantId)
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", unitPosition failed for participantId=" << participantId;
return false;
}
switch (usp)
{
case FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition::Center:
unitPositionOut = up.positionCenter();
return true;
break;
case FilterManagement::SymbolAppearanceSettings::UnitSymbolPosition::Leader:
unitPositionOut = up.positionLeader();
return true;
break;
} // switch
return false;
}
void ParticipantsMoveDialog::doSetSimulatedPositionRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate)
{
// single participant or unit should be move to _one_ origin:
const int participantId = participantData.id();
if (participantId <= 0) // sanity
return;
ParticipantManagement::SetSimulatedPosition req;
bool bAll = m_ui->cbAll->isChecked();
bool bAskOutdated = true;
if (bAll)
req.participantId(-1);
else
{
const ParticipantManagement::TypeClass tc = m_ppmDtc->type(participantData.typeId()).typeClass();
DEBUG_LOG(m_logger) << "ParticipantId=" << participantData.id()
<< " EquipmentNr=" << participantData.equipmentNumber()
<< " onGetCoordinate x=" << coordinate.x() << " y=" << coordinate.y()
<< ", tc=" << tc;
if (participantData.id() <= 0)
return;
req.participantId(participantData.id());
bAskOutdated = m_ppmDtc->type(participantData.typeId()).typeClass() == ParticipantManagement::TypeClass_def::Unit;
}
bool bOnlyOutdated = false;
if (bAskOutdated)
{
QHash<LtsWidgets::Button, QString> texts({{LtsWidgets::Button::Yes, tr("All")},
{LtsWidgets::Button::No, tr("Only outdated")}
});
auto b = LtsWidgets::LtsMessageDialog::showMessage(this,
tr("Do you want to move all participants or only outdated ones?"),
windowTitle(),
LtsWidgets::Behaviour::Modal,
LtsWidgets::Button::Yes | LtsWidgets::Button::No,
texts);
if (b == LtsWidgets::Button::Cancel)
return;
bOnlyOutdated = (b == LtsWidgets::Button::No);
}
req.onlyOutdatedParticipants(bOnlyOutdated);
req.position(Core::GeoPosition(coordinate.x(), coordinate.y(), 0.0));
m_requestHelper->startSingleRequest([req, this]()
{
return m_ppmFtc->setSimulatedPositionRequest(req, this);
});
}
void ParticipantsMoveDialog::doSetSimulatedPositionRelativeRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate)
{
// Unit is selected and should be moved relative to it´s current origin:
const int participantId = participantData.id();
if (participantId <= 0) //sanity
return;
Core::GeoPosition unitPositionOut;
if (!getUnitPosition(participantId, unitPositionOut))
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition failed for participantId=" << participantId;
return;
}
INFO_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition for participantId=" << participantId
<< ", unitPositionOut: lon=" << unitPositionOut.lon() << " - lat=" << unitPositionOut.lat();
LtsCoordTrans::UtmCoordinate curUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(unitPositionOut.lon(), unitPositionOut.lat());
LtsCoordTrans::UtmCoordinate desiredUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(coordinate);
QPointF offset = desiredUnitPosUtm.relativeTo(curUnitPosUtm);
if (offset.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", required offset is zero. not expected... return";
return;
}
ParticipantManagement::SetSimulatedPositionRelative req;
req.participantId(participantId);
req.positionOffsetX(offset.x());
req.positionOffsetY(offset.y());
DEBUG_LOG(m_logger) << "SetSimulatedPositionRelative = " << req;
m_requestHelper->startSingleRequest([req, this]()
{
return m_ppmFtc->setSimulatedPositionRelativeRequest(req, this);
});
}
void ParticipantsMoveDialog::doSetSimulatedParticipantFormationRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate, const QString &formationData)
{
// Unit is selected and should be moved relative to it´s current origin:
const int participantId = participantData.id();
if (participantId <= 0) //sanity
return;
Core::GeoPosition unitPositionOut;
if (!getUnitPosition(participantId, unitPositionOut))
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition failed for participantId=" << participantId;
return;
}
INFO_LOG(m_logger) << LOGFUNCTION << ", getUnitPosition for participantId=" << participantId
<< ", unitPositionOut: lon=" << unitPositionOut.lon() << " - lat=" << unitPositionOut.lat();
LtsCoordTrans::UtmCoordinate curUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(unitPositionOut.lon(), unitPositionOut.lat());
LtsCoordTrans::UtmCoordinate desiredUnitPosUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(coordinate);
const QPointF offset = desiredUnitPosUtm.relativeTo(curUnitPosUtm);
if (offset.isNull())
{
ERROR_LOG(m_logger) << LOGFUNCTION << ", required offset is zero. not expected... return";
return;
}
ParticipantManagement::SetSimulatedParticipantFormation req;
req.participantId(participantId);
req.position(Core::GeoPosition(coordinate.x(), coordinate.y(), 0.0));
req.positionOffsetX(offset.x());
req.positionOffsetY(offset.y());
req.formation(formationData.toStdString());
m_requestHelper->startSingleRequest([req, this]()
{
return m_ppmFtc->setSimulatedParticipantFormationRequest(req, this);
});
}
ParticipantManagement::ParticipantData ParticipantsMoveDialog::participantFromIndex(const QModelIndex &idx) const
{
return m_participantModel->getParticipantData(idx);
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,206 @@
/**
* @RDE_HEADER@
* GUI Plugin for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02
*/
#pragma once
//Lts
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsSession/lts_session.h>
#include "participant_move_dialog.h"
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include "participants_move_model.h"
//DDS
#include <PluginInterfaces/gui_plugin_interface.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <CentralEffectSimulation/ces_dtc.h>
#include <AreaEffectSimulation/aes_dtc.h>
#include <AssetManagement/asm_ftc.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/ces_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participants_gui_plugin_interface.h>
#include "logger.h"
//Qt
#include <QJsonDocument>
#include <QJsonObject>
#include <QVariantMap>
namespace Ui
{
class ParticipantMoveDialog;
}
namespace CentralEffectSimulation
{
// --------------------------------------------------------
// ParticipantMoveDialog
// --------------------------------------------------------
class ParticipantsMoveDialog : public LtsWidgets::LtsDialog
, protected CentralEffectSimulation::Interface::Ftc::SimulatedMovementRemoveByParticipantIdReplyHandler
, protected ParticipantManagement::Interface::Ftc::SetSimulatedPositionReplyHandler
, protected ParticipantManagement::Interface::Ftc::SetSimulatedPositionRelativeReplyHandler
, protected ParticipantManagement::Interface::Ftc::SetSimulatedParticipantFormationReplyHandler
{
Q_OBJECT
public:
explicit ParticipantsMoveDialog(const QString &menuGroup, QWidget *parent = nullptr);
~ParticipantsMoveDialog();
bool init(LtsSession::LtsSession *session,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<CentralEffectSimulation::Interface::Dtc> &cesDtc,
const std::shared_ptr<ParticipantManagement::Interface::Ftc> &ppmFtc);
void onSimulatedMovementRemoveByParticipantIdReply(const Core::FunctionReplyObject &replyObject) override;
void onSetSimulatedPositionReply(const Core::FunctionReplyObject &replyObject) override;
void onSetSimulatedPositionRelativeReply(const Core::FunctionReplyObject &replyObject) override;
void onSetSimulatedParticipantFormationReply(const Core::FunctionReplyObject &replyObject) override;
enum class FormationGeometrieType : int
{
AimPoint,
Radial,
Area,
Line,
Point
};
public slots:
void onGetCoordinate(QPointF coordinate);
private:
bool getUnitPosition(int32_t participantId, Core::GeoPosition &unitPositionOut);
void doSetSimulatedPositionRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate);
void doSetSimulatedPositionRelativeRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate);
void doSetSimulatedParticipantFormationRequest(const ParticipantManagement::ParticipantData &participantData, const QPointF &coordinate, const QString &formationData);
private slots:
void closeDialogReceived(int32_t participantId);
void onModelChanged();
private:
void retranslate() override;
void onClicked();
void onRemove();
void onSetSimulatedMGRSPosition();
bool participantInUse4ExplosionCluster(const QModelIndex &participantIndex);
void changeParty();
void onSelectionChanged();
void onDoubleClicked();
void onSetPosition();
void setDialogEnable(bool enable);
bool isParticipantInUseForExplosionCluster(int id);
void tableColumnOrganiserSetting() override;
struct ParticipantTypePropertyStruct
{
QString m_propertiesStr;
bool isArtillery = false;
QString geometry = QStringLiteral("line");
double distance = -1;
double angle = -1;
QVariantMap distanceSets;
QJsonObject distanceSetsObj;
ParticipantTypePropertyStruct() {}
explicit ParticipantTypePropertyStruct(const QString &properties) : m_propertiesStr(properties)
{
setFormation(properties);
}
void setDefaultValue()
{
isArtillery = false;
geometry = QStringLiteral("line");
distance = -1;
angle = -1;
distanceSets.clear();
}
void setFormation(const QString &jsData)
{
setDefaultValue();
const QJsonObject typObj = QJsonDocument::fromJson(QByteArray::fromStdString(jsData.toStdString())).object();
if (typObj.isEmpty())
return;
isArtillery = typObj[isArtilleryStr].toBool(false);
// Formation data Object
const QJsonObject &formationObj = typObj[formationStr].toObject();
if (formationObj.isEmpty())
{
setDefaultValue();
return;
}
geometry = formationObj[geometryStr].toString(QStringLiteral("line"));
angle = formationObj[angleStr].toDouble(-1);
distance = formationObj[distanceStr].toDouble(-1);
distanceSetsObj = formationObj[distanceSetsStr].toObject();
distanceSets = distanceSetsObj.toVariantMap();
}
bool hasFormationData() const
{
if (isArtillery == false)
return true; // no need to continue artillery must be set for formation data to be changed
else
return (angle != -1) && (distance != -1);
}
QString getFormationDataObjectString() const
{
QJsonObject obj {{geometryStr, geometry},
{angleStr, angle},
{distanceStr, distance},
{distanceSetsStr, distanceSetsObj} // doesnt change. use in combobox for selection. selection used by distance
};
return QString::fromStdString(QJsonDocument(obj).toJson(QJsonDocument::Compact).toStdString());
}
const QString isArtilleryStr = QStringLiteral("isArtillery");
const QString formationStr = QStringLiteral("formation");
const QString geometryStr = QStringLiteral("geometry");
const QString angleStr = QStringLiteral("angle");
const QString distanceStr = QStringLiteral("distance");
const QString distanceSetsStr = QStringLiteral("distanceSets");
};
void setFormationAndPositioningUi(const ParticipantManagement::ParticipantData &participantData, QPointF &mgrsCoordinate, const bool &unitWithFormation);
bool removeFtc(int32_t participantId);
ParticipantManagement::ParticipantData participantFromIndex(const QModelIndex &idx) const;
private:
ParticipantMoveModel *m_participantModel{nullptr};
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
std::shared_ptr<AreaEffectSimulation::Interface::Dtc> m_aesDtc;
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmCbxIfc;
std::shared_ptr<Interface::Ftc> m_ftc;
Ui::ParticipantMoveDialog *m_ui{nullptr};
LtsSession::LtsSession *m_session{nullptr};
QString m_menuGroup;
QMap<int, ParticipantMoveDialog *> m_participantDialogMap;
LtsUtils::RequestHelper *m_requestHelper{nullptr};
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
bool m_shiftModifierWhileOnSetPosition{false};
bool m_mgrsPosEditCoordinateActive{false};
LOGGER_T m_logger;
QRectF m_trainingAreaRect;
ParticipantTypePropertyStruct m_formationProps;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ParticipantMoveDialog</class>
<widget class="QWidget" name="ParticipantMoveDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1028</width>
<height>451</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>692</width>
<height>342</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">Participant Configuration</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0">
<item row="0" column="3">
<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>
<item row="0" column="1">
<widget class="LtsWidgets::LtsComboBox" name="cbParty">
<property name="currentText">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="LtsDataView::LtsDataView" name="dvParticipants" native="true">
<property name="rootIsDecorated" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lbParty">
<property name="text">
<string>Party:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="cbAll">
<property name="text">
<string>All Participants</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsComboBox</class>
<extends>QComboBox</extends>
<header>LtsWidgets/lts_combo_box.h</header>
</customwidget>
<customwidget>
<class>LtsDataView::LtsDataView</class>
<extends>QWidget</extends>
<header>LtsDataView/lts_data_view.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>cbParty</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,80 @@
/**
* @RDE_HEADER@
* Model for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02
*/
#include "participants_move_model.h"
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
namespace CentralEffectSimulation
{
//----------------------------------------------------------------------------
ParticipantMoveModel::ParticipantMoveModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc)
: ParticipantManagement::ParticipantEditModel(parent, ppmDtc, asbIfc)
, m_logger(getLogger("ParticipantMoveModel"))
{
m_titles += tr("Simulated");
connect(m_dtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &ParticipantMoveModel::onParticipantChanged);
DEBUG_LOG(m_logger) << "ParticipantMoveModel::ParticipantMoveModel";
}
QVariant ParticipantMoveModel::data(const QModelIndex &index, int role) const
{
// ColSimulated is the last column
if (role == Qt::DisplayRole && index.column() == columnCount() - 1)
{
bool bIsSimulated = false;
if (!isSelectableBySimulation(index, &bIsSimulated))
return QVariant();
return bIsSimulated ? tr("Yes") : tr("No");
}
return ParticipantManagement::ParticipantEditModel::data(index, role);
}
void ParticipantMoveModel::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
{
Q_UNUSED(modType)
if (data.partyId() != m_partyId)
return;
INFO_LOG(m_logger) << "onParticipantChanged isSimulated=" << data.isSimulated();
onReinitModel(partyId());
emit newData();
}
bool ParticipantMoveModel::isSelectableBySimulation(const QModelIndex &index, bool *bIsSimulated) const
{
bool isSimulatable = true;
const ParticipantManagement::ParticipantData data(getParticipantData(index));
if ((data.equipmentNumber().is_set() && data.equipmentNumber().get() > 0) ||
m_dtc->type(data.typeId()).typeClass() == ParticipantManagement::TypeClass_def::Unit)
isSimulatable = false;
DEBUG_LOG(m_logger) << "ParticipantId: " << data.id()
<< " isSimulated:" << data.isSimulated()
<< " equipmentNo:" << data.equipmentNumber()
<< " typeId=" << data.typeId()
<< " modId=" << data.modId()
<< " typeClass=" << m_dtc->type(data.typeId()).typeClass()
<< " isSimulatable=" << isSimulatable;
if (bIsSimulated)
*bIsSimulated = data.isSimulated();
return isSimulatable;
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,42 @@
/**
* @RDE_HEADER@
* Model for ParticipantsMoveDialog
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2018-01-02
*/
#pragma once
#include <QObject>
#include <nglwidgets/ngltreeitem.h>
#include <Services/ParticipantManagement/ppm_dtc.h>
#include <QStringList>
//ParticipantManagement
#include <Plugins/ParticipantManagement/Gui/Common/participant_edit_model.h>
#include "logger.h"
namespace CentralEffectSimulation
{
class ParticipantMoveModel final : public ParticipantManagement::ParticipantEditModel
{
Q_OBJECT
public:
ParticipantMoveModel(QObject *parent,
const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc,
const std::shared_ptr<AdvancedSymbology::ForeignDataInterface> &asbIfc);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void newData();
private:
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
bool isSelectableBySimulation(const QModelIndex &index, bool *bIsSimulated = nullptr) const;
NGL::INGLLogger &m_logger;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,64 @@
#
# $Id$
# $HeadURL$
# $Author$
# Created by Hannes Baeuerle, SLSE, 2017-02-24
#
SET(ces_participant_uas_gui_SRCS
logger.cpp
logger.h
ces_participant_uas_gui_plugin.h
ces_participant_uas_gui_plugin.cpp
mission_plan_model.h
mission_plan_model.cpp
mission_plan_edit.h
mission_plan_edit.cpp
mission_plan_dialog.h
mission_plan_dialog.cpp
)
NGL_WRAP_UI (ces_participant_uas_gui_SRCS
mission_plan_dialog.ui
mission_plan_edit.ui
)
NGL_ADD_LIBRARY(WS CesParticipantUASGuiPlugin MODULE ${ces_participant_uas_gui_SRCS})
if (TARGET CesParticipantUASGuiPlugin)
target_sources(CesParticipantUASGuiPlugin
PRIVATE
mission_plan_model.h mission_plan_model.cpp
)
target_sources(CesParticipantUASGuiPlugin
PRIVATE
mission_plan_edit.h mission_plan_edit.cpp mission_plan_edit.ui
)
endif()
NGL_TARGET_LINK_LIBRARIES(CesParticipantUASGuiPlugin
AsbDataPluginInterface
LtsCoordTrans
LtsPrinting
PpmDataPluginInterface
PpmGuiParticipantsPluginInterface
CesDataPluginInterface
GuiPluginInterface
AsmGuiPluginInterface
ExmDataPluginInterface
Qt5::Widgets
PpmCommon
FlmDataPluginInterface
LtsUtilsGuiDds
LtsWidgets
LtsSession
LtsSessionData
LtsDataView
SituationMapGuiPluginInterface
LtsUtilsGuiDds
ltsCoordWidget
LtsUtilsSettings
)
NGL_INSTALL_TARGET(CesParticipantUASGuiPlugin)
@@ -0,0 +1,107 @@
/**
* @RDE_HEADER@
* Gui Plugin for UAS Participant
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#include "ces_participant_uas_gui_plugin.h"
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <Services/CentralEffectSimulation/ces_operator_rights.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/Gui/ParticipantUAS/mission_plan_edit.h>
#include "mission_plan_dialog.h"
#include <LtsSession/lts_session.h>
namespace CentralEffectSimulation
{
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("Plugins.Gui.Ces.ParticipantUAS"))
{
}
bool InterfaceImpl::fetchInterfaces()
{
if (!m_session->getDtc<CentralEffectSimulation::DataInterface>(m_cesDtc))
return false;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
return false;
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
return false;
return true;
}
void InterfaceImpl::clearInterfaces()
{
m_ppmDtc = nullptr;
m_ppmFtc = nullptr;
m_cesDtc = nullptr;
}
QVector<LtsWidgets::PluginData> InterfaceImpl::getActions()
{
QVector<LtsWidgets::PluginData> ret;
LtsWidgets::PluginData plData;
if (!m_session->isReplayPartition())
{
// UAS LIST
{
plData.menuGroup = menuGroup();
plData.menuText = tr("Mission Plans");
plData.menuIcon = QIcon(QLatin1String("icon:define_movement_simulation_drone.svg"));
plData.identifier = QLatin1String("Mission plans");
plData.operatorRight = OperatorRights::UasControl;
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.createWidgetFunc = [this](QWidget * parent)
{
return LtsWidgets::initDialog(new MissionPlanDialog(menuGroup(), parent),
m_session);
};
ret.append(plData);
}
// Add UAS
{
plData.menuGroup = menuGroup();
plData.menuText = tr("Add Mission plan");
plData.menuIcon = QIcon(QLatin1String("icon:define_movement_simulation_drone.svg"));
plData.identifier = QLatin1String("ParticipantUAS");
plData.operatorRight = OperatorRights::UasControl;
plData.exercisePart = LtsWidgets::ExercisePart::eExecution;
plData.createWidgetFunc = [this](QWidget * parent)
{
return onShowAddUASDialog(parent);
};
ret.append(plData);
}
}
return ret;
}
LtsWidgets::LtsDialog *InterfaceImpl::onShowAddUASDialog(QWidget *parent)
{
MissionPlanEdit *editWidget = new MissionPlanEdit(parent);
if (editWidget->init(0, m_session))
return editWidget;
delete editWidget;
return nullptr;
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,64 @@
/**
* @RDE_HEADER@
* Gui Plugin for Simulated Movement
* $Id$
* $HeadURL$
* $Author$
* Created by Gerlinde Rudolphus, SLSE, 2017-12-19
*/
#pragma once
#include <PluginInterfaces/gui_plugin_interface.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <CentralEffectSimulation/ces_dtc.h>
namespace ParticipantManagement
{
class ForeignGuiComboboxInterface;
}
namespace CentralEffectSimulation
{
class GuiPlugin final : public QObject, public GuiPluginBase::Plugin
{
Q_PLUGIN_METADATA(IID "gui:3:ces.participant_uas")
Q_INTERFACES(GuiPluginBase::Plugin)
Q_OBJECT
public:
explicit GuiPlugin() = default;
~GuiPlugin() = default;
QString pluginName() override { return QLatin1String("CesParticipantUASGui"); }
std::shared_ptr<GuiPluginBase::Interface> createGuiInterface(LtsSession::LtsSession *session) override;
bool availableInPartition(IDL::PartitionType partition) const override
{
return (partition == IDL::PartitionType::Exercise);
}
};
class InterfaceImpl final : public QObject, public GuiPluginBase::Interface
{
Q_OBJECT
public:
explicit InterfaceImpl(LtsSession::LtsSession *session);
bool fetchInterfaces() override;
void clearInterfaces() override;
QString menuGroup() const override { return tr("Air Support"); }
QVector<LtsWidgets::PluginData> getActions() override;
LtsWidgets::LtsDialog *onShowAddUASDialog(QWidget *parent);
private: // attributes
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
std::shared_ptr<CentralEffectSimulation::Interface::Dtc> m_cesDtc;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,37 @@
/**
* @RDE_HEADER@
* Building Config - logging facility
* $Id$
* $HeadURL$
* $Author$
*/
#include "logger.h"
#include <NGLLogger/NGLLoggerBootstrap.h>
namespace CentralEffectSimulation
{
LOGGER_T getLogger(const char *name)
{
static const char ns[] = "CES.";
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();
}
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* Logging for CentralEffectSimulation
* $Id$
* $HeadURL$
* $Author$
*/
#pragma once
#include <NGLLogger/INGLLogger.h>
namespace CentralEffectSimulation
{
typedef NGL::INGLLogger &LOGGER_T;
LOGGER_T getLogger(const char *name);
inline LOGGER_T getLogger(const QString &loggerName)
{
return getLogger(loggerName.toUtf8().constData());
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,341 @@
/**
* @RDE_HEADER@
* Dialog to Simulate drone
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#include <CentralEffectSimulation/ces_data_plugin_interface.h>
#include <AreaEffectSimulation/aes_data_plugin_interface.h>
#include <ParticipantManagement/ppm_data_plugin_interface.h>
#include <LtsUtilsSettings/settings.h>
#include <CentralEffectSimulation/ces_operator_rights.h>
#include "mission_plan_dialog.h"
#include "ui_mission_plan_dialog.h"
namespace CentralEffectSimulation
{
MissionPlanDialog::MissionPlanDialog(const QString &menuGroup, QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::CloseOnly)
, m_ppmDtc(nullptr)
, m_ppmFtc(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_session(nullptr)
, m_menuGroup(menuGroup)
, m_logger(getLogger("MissionPlanDialog"))
, m_ui(new Ui::MissionPlanDialog)
{
m_ui->setupUi(this);
m_updateMissionTimer.setSingleShot(true);
m_updateMissionTimer.setInterval(500);
connect(&m_updateMissionTimer, &QTimer::timeout, this, &MissionPlanDialog::enaDisa);
setOnlineHelpFilename(QStringLiteral("Situation-UAS-Mission"));
}
MissionPlanDialog::~MissionPlanDialog()
{
delete m_ui;
}
bool MissionPlanDialog::init(LtsSession::LtsSession *session)
{
m_session = session;
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
{
ERROR_LOG(m_logger) << " failed to get ppmDtc";
return false;
}
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
{
ERROR_LOG(m_logger) << " failed to get ppmFtc";
return false;
}
m_ppmDtc->enableUnitPosition();
m_ppmDtc->waitForHistoricalDataUnitPosition(1000);
delete m_missionPlanModel;
m_missionPlanModel = new MissionPlanModel(this);
m_missionPlanModel->initModel(m_ppmDtc, m_session->exerciseId());
m_missionPlanProxyModel = new MissionPlanProxyModel(this);
m_missionPlanProxyModel->setSourceModel(m_missionPlanModel);
m_ui->participantsDataView->setModel(m_missionPlanProxyModel);
//Lock Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Load, this, &MissionPlanDialog::onLockModifications);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load, false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->setText(tr("Lock"));
m_buttonBox->setIcon(LtsWidgets::DialogButton::Load, QIcon(QStringLiteral("icon:drone_remote_connection.svg")));
//hide for now
m_buttonBox->getButton(LtsWidgets::DialogButton::Load)->hide();
//unlock Button
m_buttonBox->connectButton(LtsWidgets::DialogButton::Save, this, &MissionPlanDialog::onUnlockModifications);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->setText(tr("Unlock"));
m_buttonBox->setIcon(LtsWidgets::DialogButton::Save, QIcon(QStringLiteral("icon:drone_remote_connection.svg")));
//hide for now
m_buttonBox->getButton(LtsWidgets::DialogButton::Save)->hide();
m_buttonBox->connectButton(LtsWidgets::DialogButton::Add, this, &MissionPlanDialog::onAddMissionPlan); // wird für das Verblockung missbraucht
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Add, true);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &MissionPlanDialog::onEditMissionPlan);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
m_buttonBox->connectButton(LtsWidgets::DialogButton::Remove, this, &MissionPlanDialog::onRemoveMissionPlanClicked);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
connect(m_ui->participantsDataView, &LtsDataView::LtsDataView::signalSelectionChanged, this, &MissionPlanDialog::enaDisa);
const bool &hasOperatorRightParticipantUAS = LtsSessionData::LtsSessionData::getInstance()->hasOperatorRight(OperatorRights::ParticipantMove);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setVisible(hasOperatorRightParticipantUAS);
m_buttonBox->getButton(LtsWidgets::DialogButton::Add)->setVisible(hasOperatorRightParticipantUAS);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::missionPlanChanged,
this, &MissionPlanDialog::onMissionPlanChanged);
connect(m_ui->participantsDataView, &LtsDataView::LtsDataView::doubleClicked, this, &MissionPlanDialog::onEditMissionPlan);
return true;
}
void MissionPlanDialog::onModifyMissionPlanReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MissionPlanDialog::onRemoveMissionPlanReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
}
void MissionPlanDialog::retranslate()
{
translate(m_ui, tr("UAS Mission Plans"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setText(tr("Edit"));
m_buttonBox->getButton(LtsWidgets::DialogButton::Remove)->setText(tr("Delete"));
}
bool MissionPlanDialog::removeMissionPlan(int32_t missionplanId)
{
if (missionplanId <= 0)
return false;
ParticipantManagement::RemoveMissionPlanRequest req(missionplanId);
m_requestHelper->startSingleRequest([req, this]()
{
return m_ppmFtc->removeMissionPlanRequest(req, this);
});
return m_requestHelper->startRequests();
}
MissionPlanDialog::WayPointsStatus MissionPlanDialog::wayPointCurrentStatus(const ParticipantManagement::MissionPlan &mp) const
{
WayPointsStatus state = WayPointsStatus::Undefined;
//prepared
if (mp.missionStart() > m_session->partitionTime())
return WayPointsStatus::Prepared;
else if (mp.itemsFulfilled() != static_cast<int32_t>(mp.items().size()))
return WayPointsStatus::Active;
else if (mp.itemsFulfilled() == static_cast<int32_t>(mp.items().size()))
return WayPointsStatus::Expired;
//aborted
WARNING_LOG(m_logger)<<" -- Status Wegpunktkette Abgebrochen muss definiert werden";
return state;
}
bool MissionPlanDialog::canBeLocked() const
{
auto missionPlan = currentMissionPlan();
if (missionPlan.id()<= 0)
return false;
const auto wpStatus = wayPointCurrentStatus(missionPlan);
const auto uas = m_ppmDtc->getUasByParticipantId(missionPlan.participantId(), m_session->exerciseId());
if (uas.uasState() == ProjectDataManagement::UasState_def::Manual
|| wpStatus == WayPointsStatus::Active )
return true;
return false;
}
bool MissionPlanDialog::canBeUnlocked() const
{
auto missionPlan = currentMissionPlan();
if (missionPlan.id()<= 0)
return false;
if (missionPlan.aborted())
return false;
const auto wpStatus = wayPointCurrentStatus(missionPlan);
const auto uas = m_ppmDtc->getUasByParticipantId(missionPlan.participantId(), m_session->exerciseId());
if ( uas.uasState() == ProjectDataManagement::UasState_def::Manual
|| wpStatus != WayPointsStatus::Active)
return true;
return false;
}
MissionPlanEdit *MissionPlanDialog::currentMissionPlanEditor() const
{
QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
if (indexList.isEmpty())
return nullptr;
const ParticipantManagement::MissionPlan mp = m_missionPlanModel->getRowData(indexList.front().row());
if (mp.id() < 0)
return nullptr;
return m_participantUasEditMap.value(mp.participantId(), nullptr);
}
ParticipantManagement::MissionPlan MissionPlanDialog::currentMissionPlan() const
{
QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
if (indexList.isEmpty())
return {};
return m_missionPlanModel->getRowData(indexList.front().row());
}
void MissionPlanDialog::tableColumnOrganiserSetting()
{
//LtsColumnOrganiser
m_ui->participantsDataView->setColumnsOrganiserEnabled(identifier(), true);
}
void MissionPlanDialog::enaDisa()
{
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, false);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load, false); // lock button
QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
bool bOk = !indexList.isEmpty();
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, bOk);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, bOk);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Save, bOk && canBeLocked());
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Load, bOk && canBeUnlocked()); // lock button
}
void MissionPlanDialog::onUnlockModifications()
{
auto dialog = currentMissionPlanEditor();
if (!dialog)
return;
if (canBeUnlocked())
dialog->setAllUiElementsEnabled(true);
else
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot unlock selected Mission Plan:\n mission plan still activ"));
}
void MissionPlanDialog::onLockModifications()
{
auto dialog = currentMissionPlanEditor();
if (!dialog)
return;
if (canBeLocked())
dialog->setAllUiElementsEnabled(false);
else {
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Cannot Lock selected Mission Plan."));
}
}
void MissionPlanDialog::onAddMissionPlan()
{
static QString newMissionPlanIdentifier(QStringLiteral("NewMissionPlan"));
// selecting an existing mission plan and clicking 'add' must create a new mission plan dialog as a copy of the existing mission plan
const QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
if (indexList.isEmpty())
{
addDialog(LtsWidgets::initDialog(new MissionPlanEdit(this), 0, m_session),
m_menuGroup, newMissionPlanIdentifier, LtsWidgets::LayoutArea::eDialogTab);
return;
}
const ParticipantManagement::MissionPlan mp = m_missionPlanModel->getRowData(indexList.front().row());
if (mp.id() <= 0)
{
return;
}
addDialog(LtsWidgets::initDialog(new MissionPlanEdit(this), mp.id(), m_session, true /*as copy*/),
m_menuGroup, newMissionPlanIdentifier, LtsWidgets::LayoutArea::eDialogTab);
}
void MissionPlanDialog::onRemoveMissionPlanClicked()
{
const QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
const bool isOne = (indexList.size() == 1);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Edit, isOne);
m_buttonBox->setButtonEnabled(LtsWidgets::DialogButton::Remove, false);
if (!isOne)
return;
const ParticipantManagement::MissionPlan mp = m_missionPlanModel->getRowData(indexList.front().row());
delete m_participantUasEditMap.value(mp.id());
m_participantUasEditMap.remove(mp.id());
removeMissionPlan(mp.id());
}
void MissionPlanDialog::onEditMissionPlan()
{
QModelIndexList indexList = m_ui->participantsDataView->selectedRows();
if (indexList.isEmpty())
return;
const ParticipantManagement::MissionPlan mp = m_missionPlanModel->getRowData(indexList.front().row());
if (mp.id() <= 0)
return;
const QString dialogIdentifier = QStringLiteral("Edit-MissionPlan_%1").arg(mp.id());
if (!m_participantUasEditMap.contains(mp.participantId()))
{
MissionPlanEdit *dialog = new MissionPlanEdit(this);
m_participantUasEditMap.insert(mp.participantId(), dialog);
connect(dialog, &MissionPlanEdit::editUasDialogClosed, this, &MissionPlanDialog::onEditDialogClosed);
addDialog(LtsWidgets::initDialog(dialog, mp.id(), m_session)
, m_menuGroup
, dialogIdentifier
, LtsWidgets::LayoutArea::eDialogTab);
}
else
focusDialog(m_menuGroup, dialogIdentifier, LtsWidgets::LayoutArea::eDialogTab);
}
void MissionPlanDialog::onEditDialogClosed(const int participantId)
{
m_participantUasEditMap.remove(participantId);
}
void MissionPlanDialog::onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType)
{
Q_UNUSED(data)
Q_UNUSED(modType)
m_updateMissionTimer.start();
}
} // namespace CentralEffectSimulation
@@ -0,0 +1,105 @@
/**
* @RDE_HEADER@
* Dialog to Simulate drone
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsSession/lts_session.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <CentralEffectSimulation/ces_dtc.h>
#include <CentralEffectSimulation/ces_ftc.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/ces_gui_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_participants_gui_plugin_interface.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include "mission_plan_model.h"
#include "mission_plan_edit.h"
#include <QTimer>
#include <QWidget>
namespace Ui {
class MissionPlanDialog;
}
namespace CentralEffectSimulation
{
class MissionPlanDialog : public LtsWidgets::LtsDialog
, protected ParticipantManagement::Interface::Ftc::RemoveMissionPlanReplyHandler
, protected ParticipantManagement::Interface::Ftc::ModifyMissionPlanReplyHandler
{
Q_OBJECT
public:
explicit MissionPlanDialog(const QString &menuGroup, QWidget *parent = nullptr);
~MissionPlanDialog();
bool init(LtsSession::LtsSession *session);
void onModifyMissionPlanReply(const Core::FunctionReplyObject &replyObject) override;
void onRemoveMissionPlanReply(const Core::FunctionReplyObject &replyObject) override;
enum class WayPointsStatus
{
Undefined = 0,
Prepared,
Active,
Aborted,
Expired,
};
private:
void retranslate() override;
void changeParty();
bool removeMissionPlan(int32_t missionplanId);
WayPointsStatus wayPointCurrentStatus(const ParticipantManagement::MissionPlan &mp) const;
bool canBeLocked() const;
bool canBeUnlocked() const;
MissionPlanEdit * currentMissionPlanEditor() const;
ParticipantManagement::MissionPlan currentMissionPlan() const ;
void tableColumnOrganiserSetting() override;
protected slots:
void enaDisa();
void onUnlockModifications();
void onLockModifications();
void onAddMissionPlan();
void onRemoveMissionPlanClicked();
void onEditMissionPlan();
void onEditDialogClosed(const int participantId);
void onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType);
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
LtsUtils::RequestHelper *m_requestHelper;
QTimer m_updateMissionTimer;
LtsSession::LtsSession *m_session;
QString m_menuGroup;
QMap<int, MissionPlanEdit *> m_participantUasEditMap;
LOGGER_T m_logger;
Ui::MissionPlanDialog *m_ui;
MissionPlanModel *m_missionPlanModel{nullptr};
MissionPlanProxyModel *m_missionPlanProxyModel{nullptr};
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MissionPlanDialog</class>
<widget class="QWidget" name="MissionPlanDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1177</width>
<height>290</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="LtsDataView::LtsDataView" name="participantsDataView" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</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,829 @@
/**
* @RDE_HEADER@
* Dialog to edit drone Simulation
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#include <LtsWidgets/lts_message_dialog.h>
#include <Common/LtsCoordTrans/lts_coord_widget.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_data_plugin_interface.h>
#include <Plugins/CentralEffectSimulation/ces_data_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_gui_plugin_interface.h>
#include <PluginInterfaces/gui_plugin_interface.h>
#include <ParticipantManagement/ppm_translation.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ProjectDataManagement/pdm_translation.h>
#include <ProjectDataManagement/pdm_to_string.h>
#include <FileManagement/flm_translation.h>
#include <LtsSession/lts_session_data.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
#include "mission_plan_edit.h"
#include "ui_mission_plan_edit.h"
namespace CentralEffectSimulation
{
//static constexpr double s_msConversion = 3.6; // = 3.6 Convert from [km/h] to [m/s]
//static constexpr int s_timeMilliConversion = 1000; // 1000 Convert from [s] to [ms]
MissionPlanEdit::MissionPlanEdit(QWidget *parent)
: LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::OkApplyCancel)
, m_missionPlanId(0)
, m_uiEnabled(false)
, m_sitMapGuiIfc(nullptr)
, m_ppmCbxGui(nullptr)
, m_requestHelper(new LtsUtils::RequestHelper(this))
, m_participantTimer(new QTimer(this))
, m_logger(getLogger("MissionPlanEdit"))
, m_ui(new Ui::MissionPlanEdit)
{
m_ui->setupUi(this);
m_ui->nameLineEdit->clear();
m_ui->lePrefix->setText(tr("Waypoint"));
m_uiRequirements->addRequirement({m_ui->lblMoveStart, [this]() { return hasValidEffectStart(m_ui->dteStartTime); }, tr("Begin time is smaller than current time")});
m_uiRequirements->addRequirement({m_ui->lblUASParty, [this]() {return ( !m_ui->cbParty->currentData().isNull());}});
m_uiRequirements->addRequirement({m_ui->lblUasParticipant, [this]() {return ( !m_ui->participantCBox->currentData().isNull());}});
if (!QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier))
{
m_uiRequirements->addRequirement({m_ui->lblParticipantStateText, [this]() { return m_participantReady; }});
}
connect(this, &MissionPlanEdit::signalFocused, this, &MissionPlanEdit::onFocus);
m_participantTimer->setSingleShot(true);
m_participantTimer->setInterval(500);
connect(m_participantTimer, &QTimer::timeout, this, &MissionPlanEdit::onParticipantTimerTimedout);
setOnlineHelpFilename(QStringLiteral("Situation-UAS-Mission-Edit"));
}
MissionPlanEdit::~MissionPlanEdit()
{
m_sitMapGuiIfc = nullptr;
delete m_ui;
emit editUasDialogClosed(m_participantData.id());
}
bool MissionPlanEdit::init(const int missionPlanId, LtsSession::LtsSessionDataDds *session, bool asCopy)
{
m_session = session;
m_missionPlanId = missionPlanId;
if (!m_session->getDtc<ProjectDataManagement::DataInterface>(m_pdmDtc))
{
ERROR_LOG(m_logger) << " failed to get pdmDtc";
return false;
}
if (!m_session->getDtc<ParticipantManagement::DataInterface>(m_ppmDtc))
{
ERROR_LOG(m_logger) << " failed to get ppmDtc";
return false;
}
if (!m_session->getFtc<ParticipantManagement::DataInterface>(m_ppmFtc))
{
ERROR_LOG(m_logger) << " failed to get ppmFtc";
return false;
}
if (!m_session->getForeignGuiInterface<ParticipantManagement::ForeignGuiComboboxInterface>(m_ppmCbxGui))
{
ERROR_LOG(m_logger) << " failed to get ppmCbxGui";
return false;
}
// Hide Unused Buttons for now
m_ui->cbJumpToStart->hide();
m_ui->cbRepeat->hide();
//m_ui->chargesCBox->hide();
//m_ui->chargesLabel->hide();
m_session->getForeignGuiInterface<SituationMap::ForeignGuiInterface>(m_sitMapGuiIfc);
m_buttonBox->setText(LtsWidgets::DialogButton::Edit, tr("Start Now"));
m_buttonBox->setIcon(LtsWidgets::DialogButton::Edit, QIcon(QStringLiteral("icon:media-play.svg")));
m_buttonBox->connectButton(LtsWidgets::DialogButton::Edit, this, &MissionPlanEdit::onApplyNow);
m_missionPlan = m_ppmDtc->missionPlan(m_missionPlanId);
auto cb = [this, asCopy](const ParticipantManagement::MissionPlan &mission)
{
//allow participant id of current mission to be displayed.
//for other missions if mission start is in future, and not abortet uas participants will not be displayed in the combobox
if ((((mission.participantId() == m_missionPlan.participantId()) && !asCopy ) || mission.participantId() <= 0)
&& mission.missionStart() <= m_missionPlan.missionStart() && !mission.aborted())
return;
// if mission is completed or aborted uas participant should be available.
if (static_cast<int>(mission.items().size()) == mission.itemsFulfilled() || mission.aborted())
return;
m_usedUasSet.insert(mission.participantId());
};
m_ppmDtc->missionPlans(cb);
m_ppmDtc->waitForHistoricalDataParty(1000);
m_ppmDtc->waitForHistoricalDataUAS(1000);
m_ppmDtc->waitForHistoricalDataParticipant(1000);
connect(m_ui->participantCBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int /*index*/)
{
setReady(false);
const auto pId = m_ui->participantCBox->currentData().toInt();
m_participant = m_ppmDtc->participant(pId);
const auto dpd = m_ppmDtc->dynamicParticipantData(m_participant.id());
DEBUG_LOG(m_logger) << "idx changed! pId: " << pId << ", m_participant.id(): " << m_participant.id() << ", dpd.participantId(): " << dpd.participantId();
if (dpd.participantId() < 1) // aka. no data for that uas yet, aka. not ready
{
ERROR_LOG(m_logger) << "no dynamic pdata yet for pId " << pId;
setReady(false);
return;
}
DEBUG_LOG(m_logger) << "calling onDynamicParticipantDataChanged !";
onDynamicParticipantDataChanged(dpd, DataModification::eAdded);
});
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::dynamicParticipantDataChanged,
this, &MissionPlanEdit::onDynamicParticipantDataChanged);
connect(m_ui->cbParty, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MissionPlanEdit::onPartyChanged);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::uASChanged,
this, &MissionPlanEdit::onUasChanged);
// set Party & UAS Participants Combobox
fillParties();
setUASCharges();
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::missionPlanChanged,
this, &MissionPlanEdit::onMissionPlanChanged);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::participantChanged,
this, &MissionPlanEdit::onParticipantChanged);
if (m_sitMapGuiIfc)
{
connect(m_ui->pbPosition, &QPushButton::clicked, this, &MissionPlanEdit::onGetPolyline);
connect(m_ui->pbClear, &QPushButton::clicked, this, &MissionPlanEdit::clearCoordinates);
}
else
{
m_ui->pbPosition->setEnabled(false);
m_ui->pbClear->setEnabled(false);
}
// use missionplan data as default if exist
setData(missionPlanId);
enaDisa();
if(m_participant.id() <= 0 )
setReady(false);
if (m_missionPlanId > 0 && m_session->partitionTime() > m_missionPlan.missionStart() && !asCopy)
{
enableUiElements(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(false);
}
if (asCopy)
{
m_missionPlanId = 0; // mark the edit dialog as new, which makes it a create dialog
// if the UAS from the copy already is in used we need to reset to default again
if (m_ui->participantCBox->currentIndex()<0)
m_ui->participantCBox->setCurrentIndex(0);
}
return true;
}
void MissionPlanEdit::retranslate()
{
translate(m_ui, ((m_missionPlanId <= 0) ? QString() : QString::fromStdString(m_missionPlan.name())), m_missionPlanId <= 0, tr("UAS-Waypoints"));
}
void MissionPlanEdit::setReady(bool isReady)
{
m_participantReady = isReady;
m_ui->lblParticipantState->setText(QStringLiteral("<span style=\"color:#%1;\">%2</span>")
.arg(isReady ? QStringLiteral("00dd00") : QStringLiteral("dd0000"))
.arg(isReady ? tr("Ready") : tr("Not ready")));
}
// stolen from Lts/Plugins/ParticipantManagement/Gui/ParticipantInfo/participant_info_dialog.cpp
void MissionPlanEdit::onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType)
{
if (data.participantId() != m_participant.id() && data.participantId() != 0)
{
ERROR_LOG(m_logger) << "### " << data.participantId() << " != " << m_participant.id() << " (" << (int)modType << ")";
return;
}
DEBUG_LOG(m_logger) << "### " << data.participantId() << " == " << m_participant.id() << " (" << (int)modType << ") !!!";
// Do not continue on modType == DataModification::eRemove
// otherwise for example the icon would look bad (clover with black on black...)
if (modType == DataModification::eRemoved)
{
return;
}
//Current State
if (data.stateHistory().empty())
{
setReady(false);
return;
}
const auto &history = data.stateHistory();
//LasState is the last "real" state, that has a VBG <=8 (Castastrophic)
//It's not the last state received, as there can be other state changes like Sanitation, or NearMiss
auto lastState = m_ppmDtc->youngestStateInformation(history/*, true*/ /* debug */);
decltype(lastState) youngestState;
youngestState.stateTime(0);
for (const auto &si : history)
{
DEBUG_LOG(m_logger) << "StateInformation "
<< " time=" << si.stateTime()
<< " vulnerabilityBits=" << si.vulnerabilityBits()
<< " vulnerabilityKindId=" << si.vulnerabilityKindId();
if ( youngestState.stateTime() < si.stateTime())
youngestState = si;
}
setReady(youngestState.vulnerabilityState() == ProjectDataManagement::VulnerabilityState::CombatReady);
}
void MissionPlanEdit::onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType)
{
Q_UNUSED(modType)
if (data.id() != m_missionPlanId)
{
// Check, if mission is completed
if (static_cast<int>(data.items().size()) != data.itemsFulfilled())
return;
if (m_usedUasSet.contains(data.participantId()))
{
m_usedUasSet.remove(data.participantId());
fillParticipants();
}
return;
}
bool enabled;
if (m_session->partitionTime() > m_missionPlan.missionStart() && !m_missionPlan.aborted())
enabled = false;
else
enabled = true;
enableUiElements(enabled);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(enabled);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(enabled);
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(enabled);
if (static_cast<int>(data.items().size()) == data.itemsFulfilled()
&& m_usedUasSet.remove(data.participantId()))
fillParticipants();
}
void MissionPlanEdit::onModifyMissionPlanReply(const Core::FunctionReplyObject &replyObject)
{
m_requestHelper->requestReply(replyObject);
if (!replyObject.error())
m_sitMapGuiIfc->removePreviewObject();
}
void MissionPlanEdit::onSetMissionActionFulfilledReply(const Core::FunctionReplyObject &replyObject)
{
DEBUG_LOG(m_logger)<<" -- MissionPlanEdit - onSetMissionActionFulfilledReply: "<<replyObject.error();
}
QStringList MissionPlanEdit::tableColLabelList() const
{
QStringList wayPointsHeaders;
wayPointsHeaders << tr("Identifier")
<< tr("Position")
<< tr("Altitude")
<< tr("Idle Time [s]")
<< tr("Charges");
return wayPointsHeaders;
}
void MissionPlanEdit::setAllUiElementsEnabled(bool enable)
{
enableUiElements(enable);
}
ParticipantManagement::MissionPlan MissionPlanEdit::missionPlan() const
{
return m_missionPlan;
}
bool MissionPlanEdit::isUiEnabled() const
{
return m_uiEnabled;
}
void MissionPlanEdit::enaDisa()
{
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0));
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled((m_ui->tableWidget->rowCount() > 0));
}
bool MissionPlanEdit::apply()
{
// check uas switched to manual mode before proceeding
ParticipantManagement::UAS uasP = m_ppmDtc->getUasByParticipantId(m_ui->participantCBox->currentData().toInt(), m_session->exerciseId());
if (uasP.uasState() == ProjectDataManagement::UasState_def::Manual
&& uasP.participantId() != m_missionPlan.participantId())
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Waypoints can't be saved!: Uas switched to %1-Mode").arg(ProjectDataManagement::toString(uasP.uasState())));
return false;
}
ParticipantManagement::ModifyMissionPlanRequest req;
req.id(m_missionPlanId);
req.missionStart(m_ui->dteStartTime->msecsSinceEpoch());
req.participantId(m_ui->participantCBox->currentData().toInt());
req.jumpToStart(false);
req.repeat(false);
req.name(m_ui->nameLineEdit->text().toStdString());
req.items(itemsRequestContent());
return m_requestHelper->startSingleRequest([this, req]()
{
return m_ppmFtc->modifyMissionPlanRequest(req, this);
});
}
void MissionPlanEdit::clearCoordinates()
{
if (m_ui)
{
m_ui->tableWidget->clearContents();
m_ui->tableWidget->setRowCount(0);
enaDisa();
}
// remove PreviewObject:
if ( m_sitMapGuiIfc && this->amIFocused())
m_sitMapGuiIfc->removePreviewObject();
}
void MissionPlanEdit::clearContent()
{
m_ui->lePrefix->clear();
m_ui->cbRepeat->setChecked(false);
//m_ui->cbJump->setChecked(false);
clearCoordinates();
}
void MissionPlanEdit::enableUiElements(bool enable)
{
m_ui->tableWidget->setEnabled(enable);
m_ui->pbPosition->setEnabled(enable);
m_ui->pbClear->setEnabled(enable);
m_ui->spIdleTime->setEnabled(enable);
m_ui->dteStartTime->setEnabled(enable);
m_ui->cbParty->setEnabled(enable);
m_ui->participantCBox->setEnabled(enable);
m_ui->chargesCBox->setEnabled(enable);
m_ui->nameLineEdit->setEnabled(enable);
m_ui->lePrefix->setEnabled(enable);
m_ui->cbRepeat->setEnabled(enable);
m_ui->cbJumpToStart->setEnabled(enable);
m_ui->spAltitude->setEnabled(false);
m_uiEnabled = enable;
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0 && !enable)); // in case edit is blocked by user
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled((m_ui->tableWidget->rowCount() > 0 && !enable)); // in case edit is blocked by user
}
bool MissionPlanEdit::hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const
{ // if there is visible a enabled/disable checkbox -> also allow 0 as effect start
const bool bEmptyAllowed = dte->isCheckable();
const auto ms = dte->msecsSinceEpoch();
// no effect start -> ok
if (bEmptyAllowed && ms == 0)
return true;
return ms > m_session->partitionTime();
}
void MissionPlanEdit::initTableHeader()
{
m_ui->tableWidget->setColumnCount(tableColLabelList().count());
m_ui->tableWidget->setHorizontalHeaderLabels(tableColLabelList());
m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
}
void MissionPlanEdit::insertPos(const WayPointParam &wpp)
{
const int rowCount = m_ui->tableWidget->rowCount();
// insert waypoint label
m_ui->tableWidget->insertRow(rowCount);
QLineEdit *le = new QLineEdit;
le->setText(wpp.identifier);
m_ui->tableWidget->setCellWidget(rowCount, Name, le);
//insert Coordinates
LtsCoordWidget::LtsCoordWidget *wdg = new LtsCoordWidget::LtsCoordWidget();
wdg->setCoordinate(wpp.lon, wpp.lat);
wdg->setObjectName(QStringLiteral("positionEdit_") + QString::number(rowCount));
wdg->setDisplayType(LtsCoordWidget::LtsCoordWidget::DisplayType::MGRS);
m_ui->tableWidget->setCellWidget(rowCount, Position, wdg);
// insert Altitude [m]
QSpinBox *sbAltitude = new QSpinBox;
sbAltitude->setMinimum(0);
sbAltitude->setMaximum(120);
sbAltitude->setValue(wpp.z);
m_ui->tableWidget->setCellWidget(rowCount, Altitude, sbAltitude);
// insert Idle Time [sec]
QSpinBox *sbDelay = new QSpinBox;
sbDelay->setMinimum(m_ui->spIdleTime->minimum());
sbDelay->setMaximum(m_ui->spIdleTime->maximum());
sbDelay->setValue(wpp.idleTime);
m_ui->tableWidget->setCellWidget(rowCount, IdleTime, sbDelay);
// insert charges
QComboBox *ccbox = new QComboBox;
ccbox->insertItem(m_ui->chargesCBox->count(), tr("Undefined"));
for(const auto &c : m_uasCharges.toStdMap())
{
ccbox->addItem(c.second, c.first);
}
int idx = ccbox->findData(QVariant::fromValue(wpp.chargeTypeId));
ccbox->setCurrentIndex(idx > 0 ? idx : 0 );
m_ui->tableWidget->setCellWidget(rowCount, Charges, ccbox);
}
void MissionPlanEdit::showPreview(bool show)
{
if (m_sitMapGuiIfc)
{
if (show)
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
else
m_sitMapGuiIfc->removePreviewObject();
}
}
const std::vector<ParticipantManagement::MissionItem> MissionPlanEdit::itemsRequestContent()
{
const int missionItemCount = m_ui->tableWidget->rowCount();
std::vector<ParticipantManagement::MissionItem> missionItems;
using ParticipantManagement::MissionActionType;
const QVector<MissionActionType> actiontypes{
MissionActionType::MoveTo, MissionActionType::Loiter, MissionActionType::Attack}; // first action always MoveTo
int itemNumber = 0;
for (int i = 0; i < missionItemCount; i++)
{
ParticipantManagement::MissionItem msi;
QWidget *nameWidget = m_ui->tableWidget->cellWidget(i, Name);
const QString name = static_cast<QLineEdit *>(nameWidget)->text();
QWidget *altitudeWidget = m_ui->tableWidget->cellWidget(i, Altitude);
const int altitude = static_cast<QSpinBox *>(altitudeWidget)->value();
QWidget *posWidget = m_ui->tableWidget->cellWidget(i, Position);
const QPointF point = static_cast<LtsCoordWidget::LtsCoordWidget *>(posWidget)->coordinate();
Core::GeoPosition geoPos(point.x(), point.y(), altitude);
QWidget *idleTimeWidget = m_ui->tableWidget->cellWidget(i, IdleTime);
const int idleTime = static_cast<QSpinBox *>(idleTimeWidget)->value();
QWidget *chargesWidget = m_ui->tableWidget->cellWidget(i, Charges);
const int chargeTypeId = static_cast<QComboBox *>(chargesWidget)->currentData().toInt();
// phase 1 // moveTo
// phase 2 // idleTime move
// phase 3 // attack
const QString &msiName = name;
int actionNumber = 0;
const QString &msaName = QStringLiteral("%1_%2").arg(m_ui->nameLineEdit->text()).arg(name);
{
ParticipantManagement::MissionAction actionMoveTo;
actionMoveTo.actionType(ParticipantManagement::MissionActionType::MoveTo);
actionMoveTo.duration(0); // not define hier
actionMoveTo.actionNumber(actionNumber++);
actionMoveTo.name(msaName.toStdString());
actionMoveTo.itemNumber(itemNumber);
actionMoveTo.planId(m_missionPlan.id());
QJsonObject jsoMoveTo;
jsoMoveTo.insert(QStringLiteral("location_x"), point.x());
jsoMoveTo.insert(QStringLiteral("location_y"), point.y());
jsoMoveTo.insert(QStringLiteral("location_z"), altitude); //
const QString props = QString::fromUtf8(QJsonDocument(jsoMoveTo).toJson(QJsonDocument::Compact));
actionMoveTo.properties(props.toStdString());
msi.actions().push_back(actionMoveTo);
}
if (idleTime > 0)
{
ParticipantManagement::MissionAction actionLoiter;
actionLoiter.actionType(ParticipantManagement::MissionActionType::Loiter);
actionLoiter.duration(idleTime); // idleTime
actionLoiter.actionNumber(actionNumber++);
actionLoiter.itemNumber(itemNumber);
actionLoiter.name(msaName.toStdString());
actionLoiter.planId(m_missionPlan.id());
msi.actions().push_back(actionLoiter);
}
if (chargeTypeId > 0)
{
ParticipantManagement::MissionAction actionAttack;
actionAttack.actionType(ParticipantManagement::MissionActionType::Attack);
actionAttack.duration(idleTime); // idleTime
actionAttack.actionNumber(actionNumber++);
actionAttack.itemNumber(itemNumber);
actionAttack.name(msaName.toStdString());
actionAttack.planId(m_missionPlan.id());
QJsonObject jsoAttack;
jsoAttack.insert(QStringLiteral("location_x"), point.x());
jsoAttack.insert(QStringLiteral("location_y"), point.y());
jsoAttack.insert(QStringLiteral("location_z"), 0); //
jsoAttack.insert(QStringLiteral("chargeTypeId"), chargeTypeId); // chargeTypeID
const QString props = QString::fromUtf8(QJsonDocument(jsoAttack).toJson(QJsonDocument::Compact));
actionAttack.properties(props.toStdString());
msi.actions().push_back(actionAttack);
}
msi.itemNumber(itemNumber++);
msi.location(geoPos);
msi.name(msiName.toStdString());
missionItems.push_back(msi);
}
return missionItems;
}
void MissionPlanEdit::setUASCharges()
{
const auto chargesForGearClass = m_pdmDtc->chargeTypes();
m_ui->chargesCBox->clear();
m_ui->chargesCBox->insertItem(m_ui->chargesCBox->count(), tr("Undefined"));
for (const ProjectDataManagement::ChargeType &chargeType : qAsConst(chargesForGearClass))
{
// NOTE: igniterType/IgniterFunciton = 0 as long as MissionPlan does not contain values
if (!m_pdmDtc->isUasDroppable(chargeType.id(),0,0))
continue;
DEBUG_LOG(m_logger) << " fillCharges"
<< ", id=" << chargeType.id()
<< ", name= " << chargeType.name();
m_ui->chargesCBox->addItem(QString::fromStdString(chargeType.name()), chargeType.id());
m_uasCharges.insert(chargeType.id(), QString::fromStdString(chargeType.name()));
}
m_ui->chargesCBox->setCurrentIndex(0);
}
void MissionPlanEdit::setData(int mpId)
{
initTableHeader();
if (mpId < 0 )
return;
m_missionPlan = m_ppmDtc->missionPlan(mpId);
m_participantData = m_ppmDtc->participant(m_missionPlan.participantId());
m_ui->dteStartTime->setMinimumTimeMSec(m_session->partitionTime());
m_ui->dteStartTime->setRetrieveCurrentTimeCallback([this](){return m_session->partitionTime();});
m_ui->dteStartTime->setMsecsSinceEpoch(m_missionPlan.missionStart());
m_ui->nameLineEdit->setText(QString::fromStdString(m_missionPlan.name()));
// get/set current party
if (m_participantData.partyId() > 0)
{
const int partyIdx = m_ui->cbParty->findData(QVariant::fromValue(m_participantData.partyId()));
m_ui->cbParty->setCurrentIndex(partyIdx);
const int ppIdx = m_ui->participantCBox->findData(QVariant::fromValue(m_missionPlan.participantId()));
m_ui->participantCBox->setCurrentIndex(ppIdx);
}
for (const auto &item : qAsConst(m_missionPlan.items()) )
{
const std::vector<ParticipantManagement::MissionAction> &msaVec = item.actions();
WayPointParam wpp;
wpp.identifier = QString::fromStdString(item.name());
wpp.lat = item.location().lat();
wpp.lon = item.location().lon();
wpp.z = item.location().z();
for (auto const &msa : msaVec)
{
if (msa.actionType() == ParticipantManagement::MissionActionType::Loiter)
wpp.idleTime = msa.duration();
if (msa.actionType() == ParticipantManagement::MissionActionType::Attack)
{
const QJsonObject &obj = QJsonDocument::fromJson(QByteArray::fromStdString(msa.properties())).object();
wpp.chargeTypeId = obj.value(QLatin1String("chargeTypeId")).toInt();
}
}
insertPos(wpp);
}
//
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled((m_ui->tableWidget->rowCount() > 0));
}
void MissionPlanEdit::fillParties()
{
m_ppmCbxGui->fillPartyComboBox(m_ui->cbParty);
m_ui->cbParty->setCurrentIndex(0);
fillParticipants();
}
void MissionPlanEdit::fillParticipants()
{
QVector<ParticipantManagement::Participant> participants;
const int partyId = m_ui->cbParty->currentData().toInt();
gatherUASParticipants(partyId, participants);
m_ui->participantCBox->clear();
for (const auto &participant : participants)
{
QString uasString = QStringLiteral("%1 (%2)").arg(m_ppmDtc->hierarchyFromParticipant(participant.id()));
if (uasString.isEmpty() || m_usedUasSet.contains(participant.id()))
continue;
const ParticipantManagement::UAS &uasP = m_ppmDtc->getUasByParticipantId(participant.id(), m_session->exerciseId());
uasString = uasString.arg(ProjectDataManagement::toString(uasP.uasState()));
m_ui->participantCBox->addItem(uasString, participant.id());
}
if (m_missionPlan.id() > 0)
m_ui->participantCBox->setCurrentIndex(m_ui->participantCBox->findData(QVariant::fromValue(m_missionPlan.participantId())));
//Fallback to first entry
if (m_ui->participantCBox->currentIndex()<0)
m_ui->participantCBox->setCurrentIndex(0);
}
void MissionPlanEdit::gatherUASParticipants(int partyId, QVector<ParticipantManagement::Participant> &participant)
{
auto cb = [this, &partyId, &participant](const ParticipantManagement::Participant &p)
{
if (p.isDeleted() || p.partyId() != partyId)
return;
const ParticipantManagement::ParticipantData &ppData = m_ppmDtc->convertParticipantToParticipantData(p);
const ParticipantManagement::Type &&ppType = m_ppmDtc->type(ppData.typeId());
const QJsonObject typeProperties(QJsonDocument::fromJson(QByteArray::fromStdString(ppType.properties())).object());
if (typeProperties.isEmpty()
|| ppType.typeClass() != ParticipantManagement::TypeClass::Aircraft
|| !typeProperties[QStringLiteral("isUAS")].toBool(false))
return;
participant.push_back(p);
};
m_ppmDtc->participants(cb);
}
/*!
* \brief ParticipantUASEdit::onParticipantTimerTimedout
* method is called when an participant is updated. Note that onParticipantTimerTimedout()
* will be called by once even if many onParticipantChanged signal come in.
*/
void MissionPlanEdit::onParticipantTimerTimedout()
{
fillParticipants();
}
void MissionPlanEdit::onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType)
{
Q_UNUSED(data)
Q_UNUSED(modType)
m_participantTimer->start();
}
void MissionPlanEdit::onPartyChanged()
{
m_ui->participantCBox->clear();
fillParticipants();
}
void MissionPlanEdit::onGetPolyline()
{
if (!m_sitMapGuiIfc)
return;
if (m_sitMapGuiIfc->mapMode() != SituationMap::MapMode::MapMode_2D)
{
LtsWidgets::LtsMessageDialog::showMessage(this, tr("Only available in 2D mode"));
return;
}
QPolygonF coordinates;
int i = 0;
while (true)
{
LtsCoordWidget::LtsCoordWidget *w = findChild<LtsCoordWidget::LtsCoordWidget *>(QStringLiteral("positionEdit_%1").arg(i));
if (!w)
break;
if (!w->coordinate().isNull())
coordinates << w->coordinate();
++i;
}
m_sitMapGuiIfc->getPolyline(this,
SLOT(onPolylineData(QPolygonF)),
nullptr,
2,
11,
-1,
-1,
coordinates);
}
void MissionPlanEdit::onPolylineData(const QPolygonF &polyline)
{
DEBUG_LOG(m_logger) << LOGFUNCTION << " numberOfPoints: " << polyline.size();
if (polyline.size() < 2)
return;
m_polyline = polyline;
clearCoordinates();
for (int i = 0; i < polyline.size(); i++)
{
WayPointParam wp;
wp.lon = polyline.at(i).x();
wp.lat = polyline.at(i).y();
wp.identifier = m_ui->lePrefix->text() + QLatin1Char('_') + QString::number(i + 1);
wp.z = m_ui->spAltitude->value();
wp.idleTime = m_ui->spIdleTime->value();
wp.chargeTypeId = m_ui->chargesCBox->currentIndex();
insertPos(wp);
}
// create PreviewObject:
m_sitMapGuiIfc->displayPreviewObject(this, polyline, false);
enaDisa();
}
void MissionPlanEdit::onFocus()
{
showPreview(true);
m_sitMapGuiIfc->displayPreviewObject(this, m_polyline, false);
}
void MissionPlanEdit::onApplyNow()
{
QDateTime dateTime = QDateTime::fromMSecsSinceEpoch(m_session->partitionTime());
m_ui->dteStartTime->setMsecsSinceEpoch(dateTime.addSecs(10).toMSecsSinceEpoch()); //set time first THEN check for requirements
if (m_ui->tableWidget->rowCount() < 2 || !m_uiRequirements->checkRequirements())
return;
if (apply())
{
enableUiElements(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Edit)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(false);
m_buttonBox->getButton(LtsWidgets::DialogButton::Apply)->setEnabled(false);
}
}
void MissionPlanEdit::onUasChanged(const ParticipantManagement::UAS &uas)
{
Q_UNUSED(uas)
const int ppId = m_ui->participantCBox->currentData().toInt();
fillParticipants();
const int index = m_ui->participantCBox->findData(ppId);
if( index < 0)
return;
m_ui->participantCBox->setCurrentIndex(index);
}
}// namspace CentralEffectSimulation
@@ -0,0 +1,137 @@
/**
* @RDE_HEADER@
* Dialog to edit drone Simulation
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#pragma once
#include <LtsWidgets/lts_dialog.h>
#include <LtsWidgets/lts_frameless_dialog.h>
#include <LtsSession/lts_session.h>
#include <CentralEffectSimulation/ces_ftc.h>
#include <Plugins/SituationMapPlugin/situation_map_gui_plugin_interface.h>
#include <Plugins/FileManagement/flm_explorer_gui_plugin_interface.h>
#include <Plugins/ProjectDataManagement/pdm_data_plugin_interface.h>
#include <Plugins/ParticipantManagement/ppm_gui_combobox_plugin_interface.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <CentralEffectSimulation/ces_dtc.h>
#include <LtsWidgets/lts_date_time_edit.h>
#include <LtsUtilsGuiDds/request_helper.h>
#include "logger.h"
#include <QWidget>
namespace Ui {
class MissionPlanEdit;
}
namespace CentralEffectSimulation
{
struct WayPointParam
{
double lon;
double lat;
double z = 0.0;
int idleTime = 0;
double speed = 0.0;
int chargeTypeId = -1;
QString identifier;
};
class MissionPlanEdit : public LtsWidgets::LtsDialog
, protected ParticipantManagement::Interface::Ftc::ModifyMissionPlanReplyHandler
, protected ParticipantManagement::Interface::Ftc::SetMissionActionFulfilledReplyHandler
{
Q_OBJECT
public:
enum SegmentColumns
{
Name,
Position,
Altitude,
IdleTime, // [sec]
Charges
};
explicit MissionPlanEdit(QWidget *parent = nullptr);
~MissionPlanEdit();
bool init(const int missionPlanId, LtsSession::LtsSessionDataDds *session, bool asCopy = false);
void retranslate() override;
void onModifyMissionPlanReply(const Core::FunctionReplyObject &replyObject) override;
void onSetMissionActionFulfilledReply(const Core::FunctionReplyObject &replyObject) override;
QStringList tableColLabelList() const;
void setAllUiElementsEnabled(bool enable);
ParticipantManagement::MissionPlan missionPlan() const;
bool isUiEnabled() const;
signals:
void editUasDialogClosed(const int participantId);
private:
void enaDisa();
bool apply() override;
void clearCoordinates();
void clearContent();
void enableUiElements(bool enable);
bool hasValidEffectStart(LtsWidgets::LtsDateTimeEdit *dte) const;
void initTableHeader();
void insertPos(const WayPointParam &wpp);
void showPreview(bool show);
const std::vector<ParticipantManagement::MissionItem> itemsRequestContent();
void setUASCharges();
void setData(int mpId);
void fillParties();
void fillParticipants();
void gatherUASParticipants(int partyId, QVector<ParticipantManagement::Participant> &participant);
void setReady(bool isReady);
private slots:
void onParticipantTimerTimedout();
void onParticipantChanged(const ParticipantManagement::Participant &data, DataModification modType);
void onPartyChanged();
void onGetPolyline();
void onPolylineData(const QPolygonF &polyline); // callback for onGetPolyline()
void onFocus();
void onApplyNow();
void onUasChanged(const ParticipantManagement::UAS &uas);
void onDynamicParticipantDataChanged(const ParticipantManagement::DynamicParticipantData &data, DataModification modType);
void onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType);
private:
std::shared_ptr<FileManagement::ForeignGuiInterface> m_flmGui;
std::shared_ptr<ProjectDataManagement::Interface::Dtc> m_pdmDtc;
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
std::shared_ptr<ParticipantManagement::Interface::Ftc> m_ppmFtc;
LtsSession::LtsSessionDataDds *m_session;
ParticipantManagement::Participant m_participantData;
ParticipantManagement::MissionPlan m_missionPlan;
int m_missionPlanId;
bool m_uiEnabled;
QSet<int> m_usedUasSet;
std::shared_ptr<SituationMap::ForeignGuiInterface> m_sitMapGuiIfc;
std::shared_ptr<ParticipantManagement::ForeignGuiComboboxInterface> m_ppmCbxGui;
LtsUtils::RequestHelper *m_requestHelper;
QMap<int, QString> m_uasCharges;
QTimer *m_participantTimer; // used when participant were updated
QPolygonF m_polyline;
ParticipantManagement::Participant m_participant;
bool m_participantReady { false };
LOGGER_T m_logger;
Ui::MissionPlanEdit *m_ui;
};
}
@@ -0,0 +1,353 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MissionPlanEdit</class>
<widget class="QWidget" name="MissionPlanEdit">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>839</width>
<height>568</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0" colspan="2">
<widget class="QTableWidget" name="tableWidget">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="7" column="3">
<widget class="QLabel" name="lblParticipantState">
<property name="text">
<string notr="true">-</string>
</property>
</widget>
</item>
<item row="5" column="2" rowspan="2">
<widget class="QLabel" name="lblUasParticipant">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>UAS Participant:</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QCheckBox" name="cbJumpToStart">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Jump To Start</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2" colspan="3">
<widget class="LtsWidgets::LtsDateTimeEdit" name="dteStartTime" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="5" column="3" rowspan="2">
<widget class="QComboBox" name="participantCBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblMoveStart">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Start Time:</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="idleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Idle Time [s]:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelName">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Name:</string>
</property>
</widget>
</item>
<item row="3" column="0" rowspan="2">
<widget class="QLabel" name="chargesLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Charge Type:</string>
</property>
</widget>
</item>
<item row="5" column="1" rowspan="2">
<widget class="QComboBox" name="cbParty"/>
</item>
<item row="0" column="7">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" rowspan="2">
<widget class="QLabel" name="lblUASParty">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>UAS Units:</string>
</property>
</widget>
</item>
<item row="0" column="5" rowspan="2">
<widget class="QSpinBox" name="spIdleTime">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QCheckBox" name="cbRepeat">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Repeat</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="lblParticipantStateText">
<property name="text">
<string>Participant state:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="nameLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="1" rowspan="2" colspan="3">
<widget class="QComboBox" name="chargesCBox"/>
</item>
<item row="5" column="4">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Edit Waypoints in Map:</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Prefix:</string>
</property>
</widget>
</item>
<item row="5" column="5">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
<property name="spacing">
<number>1</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<widget class="QPushButton" name="pbPosition">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/position.svg</normaloff>:/style/position.svg</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClear">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>40</height>
</size>
</property>
<property name="toolTip">
<string/>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="icon">
<iconset>
<normaloff>:/style/remove.svg</normaloff>:/style/remove.svg</iconset>
</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>
</layout>
</item>
<item row="3" column="5">
<widget class="QLineEdit" name="lePrefix">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxLength">
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Altitude</string>
</property>
</widget>
</item>
<item row="2" column="5">
<widget class="QSpinBox" name="spAltitude">
<property name="maximum">
<number>120</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LtsWidgets::LtsDateTimeEdit</class>
<extends>QWidget</extends>
<header>LtsWidgets/lts_date_time_edit.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,235 @@
/**
* @RDE_HEADER@
* Dialog to edit drone Simulation
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#include <Plugins/ParticipantManagement/ppm_data_plugin_interface.h>
#include <LtsUtilsSettings/settings.h>
#include <ProjectDataManagement/pdm_translation.h>
#include "mission_plan_model.h"
namespace CentralEffectSimulation
{
/*!
* \brief MissionPlanModel::MissionPlanModel
* \param parent
*/
MissionPlanModel::MissionPlanModel(QObject *parent)
: LtsWidgets::LtsAbstractTableModel<ParticipantManagement::MissionPlan>(
{tr("Name"),
tr("Mission Start"),
tr("Actions [fulfilled / Count]"),
tr("Fulfilled"),
tr("Participant"),
tr("UAS State"),
tr("Current Mission"),
tr("Aborted")},
parent)
, m_ppmDtc(nullptr)
, m_logger(getLogger("MissionPlanModel"))
{
}
/*!
* \brief MissionPlanModel::data
* \param index
* \param role
* \return
*/
QVariant MissionPlanModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole || !indexIsValid(index))
return QVariant();
const ParticipantManagement::MissionPlan &mp = m_vecData.at(index.row());
switch (index.column())
{
case Columns::Name:
return QString::fromStdString(mp.name());
case Columns::MissionStart:
return QDateTime::fromMSecsSinceEpoch(mp.missionStart());
case Columns::Fulfilled:
return QDateTime::fromMSecsSinceEpoch(mp.fulfilled());
case Columns::ItemsCountAndFulfilled:
{
int actionsFulfilled = 0;
int actionsCount = 0;
for (const auto &item : mp.items())
{
actionsFulfilled += item.actionsFulfilled();
actionsCount += item.actions().size();
}
return QStringLiteral("%1/%2").arg(actionsFulfilled).arg(actionsCount);// item fulfilled / item count;
}
case Columns::Participant:
{
const auto &participant = m_ppmDtc->participant(mp.participantId());
return QString::number(mp.participantId());//QString::fromStdString(participant.designator());
}
case Columns::UasState:
{
const auto &uas = m_ppmDtc->getUasByParticipantId(mp.participantId(), m_exerciseId);
return ProjectDataManagement::toString(uas.uasState());
}
case Columns::CurrentMission:
{
return currentJob2String(mp);
}
case Columns::Aborted:
{
return mp.aborted();
}
default:
break;
}
return QVariant();
}
/*!
* \brief MissionPlanModel::initModel
* \param ppmDtc
* \return
*/
bool MissionPlanModel::initModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, int exerciseId)
{
m_ppmDtc = ppmDtc;
m_ppmDtc->enableMissionPlan(true);
m_exerciseId = exerciseId;
if (!m_ppmDtc->isUASEnabled())
m_ppmDtc->enableUAS();
m_ppmDtc->waitForHistoricalDataUAS(1000);
connect(m_ppmDtc.get(), &ParticipantManagement::Interface::Dtc::missionPlanChanged,
this, &MissionPlanModel::onMissionPlanChanged);
auto cb = [this](const ParticipantManagement::MissionPlan &msp)
{
onMissionPlanChanged(msp, DataModification::eAdded);
};
m_ppmDtc->missionPlans(cb);
return true;
}
QString MissionPlanModel::currentJob2String(const ParticipantManagement::MissionPlan &missionPlan) const
{
// get current action
// get latest actionType
ParticipantManagement::MissionAction currAction = m_ppmDtc->currentMissionAction(missionPlan.id());
if (currAction.planId() == 0 ||
static_cast<int>(missionPlan.items().size()) == missionPlan.itemsFulfilled())
return tr(" Mission Complete ");
switch (currAction.actionType().underlying())
{
case ParticipantManagement::MissionActionType::MoveTo:
{
return tr("Move to WP %1").arg(currAction.itemNumber()+1);
}
case ParticipantManagement::MissionActionType::Loiter:
{
return tr("WP %1: Loiter %2 sec.").arg(currAction.itemNumber()+1).arg(currAction.duration());
}
case ParticipantManagement::MissionActionType::Attack:
{
return tr("WP %1: Drop Charge").arg(currAction.itemNumber()+1);
}
default:
return tr("Unknown");
}
}
/*!
* \brief MissionPlanModel::onParticipantUASChanged
* \param data
* \param modType
*/
void MissionPlanModel::onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType)
{
const int id = data.id();
int row = findRowForId(id);
DEBUG_LOG(m_logger)<<"MISSION PLAN CHANGED id ( "<<data.id()<<" ) "<< modType;
switch (modType)
{
case DataModification::eModified:
{
if (row < 0)
return;
setRowData(row, data);
break;
}
case DataModification::eAdded:
{
if (row != -1)
return;
else
insertRow(data);
break;
}
case DataModification::eRemoved:
removeRow(row);
break;
}
}
/// #####################################
/// PARTICIPANT_UAS-POXYMODEL
/// #####################################
///
/*!
* \brief ParticipantUASProxyModel::setSourceModel
* \param sourceModel
*/
void MissionPlanProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
m_sourceModel = qobject_cast<MissionPlanModel*>(sourceModel);
LtsWidgets::LtsColumnFilterProxyModel::setSourceModel(sourceModel);
}
/*!
* \brief ParticipantUASProxyModel::setShowExpired
* \param show
*/
void MissionPlanProxyModel::setShowExpired(bool show)
{
m_showExpired = show;
}
/*!
* \brief ParticipantUASProxyModel::filterAcceptsRow
* \param source_row
* \param sourceParent
* \return
*/
bool MissionPlanProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
Q_UNUSED(sourceParent)
return checkFilter(sourceRow);
}
/*!
* \brief ParticipantUASProxyModel::checkFilter
* \param sourceRow
* \return
*/
bool MissionPlanProxyModel::checkFilter(int sourceRow) const
{
Q_UNUSED(sourceRow)
//const auto uas = m_sourceModel->getRowData(sourceRow);
return true;
}
}// namespace CentralEffectSimulation
@@ -0,0 +1,80 @@
/**
* @RDE_HEADER@
* Dialog to edit drone Simulation
* $Id$
* $HeadURL$
* $Author$
* Created by Steve Kemayou, ESZS, 2025-04-08
*/
#pragma once
#include <QObject>
#include <LtsWidgets/lts_abstract_table_model.h>
#include <LtsWidgets/lts_column_filter_proxy_model.h>
//#include <CentralEffectSimulation/logger.h>
#include <LtsSession/lts_session.h>
#include <LtsSession/lts_session_data.h>
#include <ParticipantManagement/ppm_dtc.h>
#include <ParticipantManagement/ppm_ftc.h>
#include <ParticipantManagement/ppm.hpp>
#include "logger.h"
namespace CentralEffectSimulation
{
class MissionPlanModel : public LtsWidgets::LtsAbstractTableModel<ParticipantManagement::MissionPlan>
{
Q_OBJECT
public:
enum Columns
{
Name,
MissionStart,
ItemsCountAndFulfilled, // item Fulfilled / item count
Fulfilled,
Participant,
UasState,
CurrentMission,
Aborted
};
explicit MissionPlanModel(QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const override final;
bool initModel(const std::shared_ptr<ParticipantManagement::Interface::Dtc> &ppmDtc, int exerciseId);
QString currentJob2String(const ParticipantManagement::MissionPlan &missionPlan) const;
private slots:
void onMissionPlanChanged(const ParticipantManagement::MissionPlan &data, const DataModification modType);
private:
std::shared_ptr<ParticipantManagement::Interface::Dtc> m_ppmDtc;
int m_exerciseId {-1};
LOGGER_T m_logger;
friend class EmergencyCallProxyModel;
};
/*!
* UASProxyModel
*/
class MissionPlanProxyModel : public LtsWidgets::LtsColumnFilterProxyModel
{
Q_OBJECT
public:
using LtsWidgets::LtsColumnFilterProxyModel::LtsColumnFilterProxyModel;
bool showExpired() const {return m_showExpired;}
void setSourceModel(QAbstractItemModel *sourceModel) override;
public slots:
void setShowExpired(bool show);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override final;
private:
bool checkFilter(int sourceRow)const;
private:
bool m_showExpired{false};
MissionPlanModel *m_sourceModel{nullptr};
};
} //namespace CentralEffectSimulation
@@ -0,0 +1,30 @@
/**
* @RDE_HEADER@
* HMI Plugin for CentralEffectSimulation (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Astrid Mueller, SGAS, 2017-08-09
*/
#pragma once
#include <PluginInterfaces/data_plugin_interface.h>
#include <CentralEffectSimulation/ces_dtc.h>
#include <CentralEffectSimulation/ces_ftc.h>
namespace CentralEffectSimulation
{
/**
* @brief The DataInterface class provides the Topics Clients only for the GUI Plugins
*/
class DataInterface : public DataPluginBase::Interface
{
public:
using DataPluginBase::Interface::Interface;
virtual std::shared_ptr<CentralEffectSimulation::Interface::Dtc> getDtc() = 0;
virtual std::shared_ptr<CentralEffectSimulation::Interface::Ftc> getFtc() = 0;
};
} // namespace CentralEffectSimulation
@@ -0,0 +1,22 @@
/**
* @RDE_HEADER@
* HMI Plugin for AlarmManagement (Interface for access from other Plugins)
* $Id$
* $HeadURL$
* $Author$
* Created by Patric Karwat, SLSE, 2016-10-05
*/
#pragma once
namespace CentralEffectSimulation
{
class ForeignGuiInterface
{
public:
ForeignGuiInterface() = default;
virtual ~ForeignGuiInterface() = default;
};
} //namespace CentralEffectSimulation