Files
qt5-legatus-legacy/Lts/Plugins/CentralEffectSimulation/Gui/ParticipantUAS/mission_plan_edit.cpp
T
2026-08-13 18:33:10 +02:00

830 lines
29 KiB
C++
Executable File

/**
* @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